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