/ Exchanges / src / adhoc / leverage.jl
leverage.jl
 1  using .Python: pytask
 2  
 3  _lev_frompos(exc, symbol, settle) = begin
 4      pos = pyfetch(exc.fetchPositions; params=LittleDict(("settle",), (settle,)))
 5      pos isa PyException && return pos
 6      this_lev = nothing
 7      for item in pos
 8          item_sym = get(item, "symbol", @pyconst(""))
 9          if Bool(item_sym == @pystr(symbol))
10              this_lev = pytofloat(get(item, "leverage", nothing))
11              break
12          end
13      end
14      @something this_lev 1.0
15  end
16  
17  _settle_from_market(exc, symbol) = begin
18      mkt = get(exc.markets, symbol, nothing)
19      @assert !isnothing(mkt) "Symbol $symbol not found in exchange markets $(nameof(exc))"
20      settle = get(mkt, "settle", nothing)
21      @assert !isnothing(settle) "Symbol does not have a settle currency"
22      settle
23  end
24  
25  _negative_lev_if_cross(mode_str, lev) =
26      if mode_str == "cross"
27          Base.negate(abs(lev))
28      elseif mode_str == "isolated"
29          abs(lev)
30      else
31          error("Margin mode $mode_str is not valid [supported: 'cross', 'isolated']")
32      end
33  
34  
35  function dosetmargin(exc::Exchange{ExchangeID{:phemex}}, mode_str, symbol;
36      hedged=false, settle=_settle_from_market(exc, symbol), lev=_lev_frompos(exc, symbol, settle)
37  )
38      task = pytask(exc.setPositionMode, hedged, symbol) # set hedged mode
39      this_lev = _negative_lev_if_cross(mode_str, lev)
40      resp = pyfetch(exc.setLeverage, this_lev, symbol)
41      if resp isa PyException
42          return resp
43      end
44      wait(task)
45      resptobool(exc, resp)
46  end
47  
48  function dosetmargin(exc::Exchange{ExchangeID{:bybit}}, mode_str, symbol;
49      hedged=false, settle=_settle_from_market(exc, symbol), lev=_lev_frompos(exc, symbol, settle)
50  )
51      @sync begin
52          if has(exc, :setPositionMode)
53              @async pyfetch(exc.setPositionMode, hedged, symbol) # hedged mode to false
54          end
55          resp = pyfetch(exc.setMarginMode, mode_str, symbol, params=LittleDict(("leverage",), (lev,)))
56          if resp isa PyException
57              msg = string(resp.v.args)
58              # mode unchanged, avoid liquidation
59              return if occursin(r"(110026)|(110011)", msg)
60                  true
61              else
62                  resp
63              end
64          else
65              Bool(get(resp, "retCode", @pyconst("1")) == @pyconst("0"))
66          end
67      end
68  end
69  
70  leverage_value(::Exchange{ExchangeID{:phemex}}, val, sym) = round(float(val), digits=2)
71  leverage_value(::Exchange{<:eids(:binance, :binanceusdm, :binancecoin)}, val, sym) = round(Int, float(val))
72  
73  function _handle_leverage(e::Exchange{<:eids(:binance, :binanceusdm, :binancecoin)}, resp)
74      if resp isa PyException
75          @debug resp
76          false
77      else
78          haskey(resp, "leverage")
79      end
80  end
81  
82  marginmode!(exc::Exchange{<:ExchangeID{:binance}}, mode, symbol; hedged=false, kwargs...) = begin
83      # setting default margin mode in the binance spot testnet triggers ccxt to
84      # use wrong api endpoints
85      if !issandbox(exc)
86          invoke(marginmode!, Tuple{Exchange,<:Any,<:Any}, exc, mode, symbol)
87      else
88          return true
89      end
90  end