Skip to content

Commit d5286fd

Browse files
committed
Add Binance Futures margin type
1 parent 85ef8a7 commit d5286fd

File tree

5 files changed

+122
-4
lines changed

5 files changed

+122
-4
lines changed

nautilus_trader/adapters/binance/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from nautilus_trader.adapters.binance.common.enums import BinanceAccountType
1818
from nautilus_trader.adapters.binance.common.enums import BinanceKeyType
1919
from nautilus_trader.adapters.binance.common.symbol import BinanceSymbol
20+
from nautilus_trader.adapters.binance.futures.enums import BinanceFuturesMarginType
2021
from nautilus_trader.config import LiveDataClientConfig
2122
from nautilus_trader.config import LiveExecClientConfig
2223
from nautilus_trader.config import PositiveInt
@@ -127,6 +128,8 @@ class BinanceExecClientConfig(LiveExecClientConfig, frozen=True):
127128
The maximum delay (milliseconds) between retries.
128129
futures_leverages : dict[BinanceSymbol, PositiveInt], optional
129130
The initial leverage to be used for each symbol. It's applicable to futures only.
131+
futures_margin_types : dict[BinanceSymbol, BinanceFuturesMarginType], optional
132+
Margin type (isolated or cross) to be used for each symbol. It's applicable to futures only.
130133
131134
Warnings
132135
--------
@@ -153,3 +156,4 @@ class BinanceExecClientConfig(LiveExecClientConfig, frozen=True):
153156
retry_delay_initial_ms: PositiveInt | None = None
154157
retry_delay_max_ms: PositiveInt | None = None
155158
futures_leverages: dict[BinanceSymbol, PositiveInt] | None = None
159+
futures_margin_types: dict[BinanceSymbol, BinanceFuturesMarginType] | None = None

nautilus_trader/adapters/binance/futures/enums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ class BinanceFuturesMarginType(Enum):
8282
Represents a Binance Futures margin type.
8383
"""
8484

85-
ISOLATED = "isolated"
86-
CROSS = "cross"
85+
ISOLATED = "ISOLATED"
86+
CROSS = "CROSSED"
8787

8888

8989
@unique

nautilus_trader/adapters/binance/futures/execution.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ def __init__(
145145
self._log.info("TRADE_LITE events will be used", LogColor.BLUE)
146146

147147
self._leverages = config.futures_leverages
148+
self._margin_types = config.futures_margin_types
148149

149150
# WebSocket futures schema decoders
150151
self._decoder_futures_user_msg_wrapper = msgspec.json.Decoder(BinanceFuturesUserMsgWrapper)
@@ -178,14 +179,27 @@ async def _update_account_state(self) -> None:
178179

179180
if self._leverages:
180181
async with TaskGroup() as tg:
181-
tasks = [
182+
leverage_tasks = [
182183
tg.create_task(self._futures_http_account.set_leverage(symbol, leverage))
183184
for symbol, leverage in self._leverages.items()
184185
]
185-
for task in tasks:
186+
for task in leverage_tasks:
186187
res: BinanceFuturesLeverage = task.result()
187188
self._log.info(f"Set default leverage {res.symbol} {res.leverage}X")
188189

190+
if self._margin_types:
191+
async with TaskGroup() as tg:
192+
margin_tasks = [
193+
(
194+
tg.create_task(self._futures_http_account.set_margin_type(symbol, type_)),
195+
symbol,
196+
type_,
197+
)
198+
for symbol, type_ in self._margin_types.items()
199+
]
200+
for _, symbol, type_ in margin_tasks:
201+
self._log.info(f"Set {symbol} margin type to {type_.value}")
202+
189203
account: MarginAccount = self.get_account()
190204
position_risks = await self._futures_http_account.query_futures_position_risk()
191205
for position in position_risks:

nautilus_trader/adapters/binance/futures/http/account.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
from nautilus_trader.adapters.binance.common.schemas.account import BinanceOrder
2323
from nautilus_trader.adapters.binance.common.schemas.account import BinanceStatusCode
2424
from nautilus_trader.adapters.binance.common.symbol import BinanceSymbol
25+
from nautilus_trader.adapters.binance.futures.enums import BinanceFuturesMarginType
2526
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesAccountInfo
2627
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesDualSidePosition
2728
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesLeverage
29+
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesMarginTypeResponse
2830
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesPositionRisk
2931
from nautilus_trader.adapters.binance.http.account import BinanceAccountHttpAPI
3032
from nautilus_trader.adapters.binance.http.client import BinanceHttpClient
3133
from nautilus_trader.adapters.binance.http.endpoint import BinanceHttpEndpoint
34+
from nautilus_trader.adapters.binance.http.error import BinanceClientError
3235
from nautilus_trader.common.component import LiveClock
3336
from nautilus_trader.common.config import PositiveInt
3437
from nautilus_trader.core.nautilus_pyo3 import HttpMethod
@@ -393,6 +396,64 @@ async def post(
393396
return self._resp_decoder.decode(raw)
394397

395398

399+
class BinanceFuturesMarginTypeHttp(BinanceHttpEndpoint):
400+
"""
401+
Margin type
402+
403+
`POST /fapi/v1/marginType`
404+
405+
References
406+
----------
407+
https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Margin-Type
408+
409+
"""
410+
411+
def __init__(
412+
self,
413+
client: BinanceHttpClient,
414+
base_endpoint: str,
415+
):
416+
methods = {
417+
HttpMethod.POST: BinanceSecurityType.TRADE,
418+
}
419+
url_path = base_endpoint + 'marginType'
420+
super().__init__(client, methods, url_path)
421+
self._resp_decoder = msgspec.json.Decoder(BinanceFuturesMarginTypeResponse)
422+
423+
class PostParameters(msgspec.Struct, omit_defaults=True, frozen=True):
424+
"""
425+
Margin type POST endpoint parameters.
426+
427+
Parameters
428+
----------
429+
symbol : BinanceSymbol
430+
marginType : str
431+
ISOLATED or CROSSED
432+
timestamp : str
433+
The millisecond timestamp of the request.
434+
recvWindow : str, optional
435+
The response receive window in milliseconds for the request.
436+
437+
"""
438+
439+
symbol: BinanceSymbol
440+
marginType: str
441+
timestamp: str
442+
recvWindow: str | None = None
443+
444+
async def post(
445+
self,
446+
params: PostParameters,
447+
) -> BinanceFuturesMarginTypeResponse:
448+
try:
449+
raw = await self._method(HttpMethod.POST, params)
450+
except BinanceClientError as e:
451+
if e.message['msg'] == 'No need to change margin type.':
452+
return BinanceFuturesMarginTypeResponse(code=200, msg='success')
453+
raise
454+
return self._resp_decoder.decode(raw)
455+
456+
396457
class BinanceFuturesAccountHttpAPI(BinanceAccountHttpAPI):
397458
"""
398459
Provides access to the Binance Futures Account/Trade HTTP REST API.
@@ -444,6 +505,10 @@ def __init__(
444505
v2_endpoint_base,
445506
)
446507
self._endpoint_futures_leverage = BinanceFuturesLeverageHttp(client, self.base_endpoint)
508+
self._endpoint_futures_margin_type = BinanceFuturesMarginTypeHttp(
509+
client,
510+
self.base_endpoint,
511+
)
447512

448513
async def query_futures_hedge_mode(
449514
self,
@@ -477,6 +542,29 @@ async def set_leverage(
477542
),
478543
)
479544

545+
async def set_margin_type(
546+
self,
547+
symbol: BinanceSymbol,
548+
margin_type: BinanceFuturesMarginType,
549+
recv_window: str | None = None,
550+
) -> BinanceFuturesMarginTypeResponse:
551+
"""
552+
Change symbol level margin type
553+
554+
:param symbol : BinanceSymbol
555+
:param margin_type : BinanceFuturesMarginType
556+
:param recv_window : str, optional
557+
:return: BinanceFuturesMarginTypeResponse
558+
"""
559+
return await self._endpoint_futures_margin_type.post(
560+
self._endpoint_futures_margin_type.PostParameters(
561+
symbol=symbol,
562+
marginType=margin_type.value,
563+
timestamp=self._timestamp(),
564+
recvWindow=recv_window,
565+
)
566+
)
567+
480568
async def set_futures_hedge_mode(
481569
self,
482570
dual_side_position: bool,
@@ -565,3 +653,5 @@ async def query_futures_position_risk(
565653
recvWindow=recv_window,
566654
),
567655
)
656+
657+

nautilus_trader/adapters/binance/futures/schemas/account.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,13 @@ class BinanceFuturesLeverage(msgspec.Struct, frozen=True):
185185
leverage: int
186186
maxNotionalValue: str
187187
symbol: str
188+
189+
190+
class BinanceFuturesMarginTypeResponse(msgspec.Struct, frozen=True):
191+
"""
192+
HTTP response from Binance Futures `POST /fapi/v1/marginType`.
193+
"""
194+
195+
code: int
196+
msg: str
197+

0 commit comments

Comments
 (0)