Skip to content

Binance Futures margin type #2660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions nautilus_trader/adapters/binance/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from nautilus_trader.adapters.binance.common.enums import BinanceAccountType
from nautilus_trader.adapters.binance.common.enums import BinanceKeyType
from nautilus_trader.adapters.binance.common.symbol import BinanceSymbol
from nautilus_trader.adapters.binance.futures.enums import BinanceFuturesMarginType
from nautilus_trader.config import LiveDataClientConfig
from nautilus_trader.config import LiveExecClientConfig
from nautilus_trader.config import PositiveInt
Expand Down Expand Up @@ -127,6 +128,8 @@ class BinanceExecClientConfig(LiveExecClientConfig, frozen=True):
The maximum delay (milliseconds) between retries.
futures_leverages : dict[BinanceSymbol, PositiveInt], optional
The initial leverage to be used for each symbol. It's applicable to futures only.
futures_margin_types : dict[BinanceSymbol, BinanceFuturesMarginType], optional
Margin type (isolated or cross) to be used for each symbol. It's applicable to futures only.

Warnings
--------
Expand All @@ -153,3 +156,4 @@ class BinanceExecClientConfig(LiveExecClientConfig, frozen=True):
retry_delay_initial_ms: PositiveInt | None = None
retry_delay_max_ms: PositiveInt | None = None
futures_leverages: dict[BinanceSymbol, PositiveInt] | None = None
futures_margin_types: dict[BinanceSymbol, BinanceFuturesMarginType] | None = None
4 changes: 2 additions & 2 deletions nautilus_trader/adapters/binance/futures/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ class BinanceFuturesMarginType(Enum):
Represents a Binance Futures margin type.
"""

ISOLATED = "isolated"
CROSS = "cross"
ISOLATED = "ISOLATED"
CROSS = "CROSSED"


@unique
Expand Down
18 changes: 16 additions & 2 deletions nautilus_trader/adapters/binance/futures/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def __init__(
self._log.info("TRADE_LITE events will be used", LogColor.BLUE)

self._leverages = config.futures_leverages
self._margin_types = config.futures_margin_types

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

if self._leverages:
async with TaskGroup() as tg:
tasks = [
leverage_tasks = [
tg.create_task(self._futures_http_account.set_leverage(symbol, leverage))
for symbol, leverage in self._leverages.items()
]
for task in tasks:
for task in leverage_tasks:
res: BinanceFuturesLeverage = task.result()
self._log.info(f"Set default leverage {res.symbol} {res.leverage}X")

if self._margin_types:
async with TaskGroup() as tg:
margin_tasks = [
(
tg.create_task(self._futures_http_account.set_margin_type(symbol, type_)),
symbol,
type_,
)
for symbol, type_ in self._margin_types.items()
]
for _, symbol, type_ in margin_tasks:
self._log.info(f"Set {symbol} margin type to {type_.value}")

account: MarginAccount = self.get_account()
position_risks = await self._futures_http_account.query_futures_position_risk()
for position in position_risks:
Expand Down
89 changes: 89 additions & 0 deletions nautilus_trader/adapters/binance/futures/http/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
from nautilus_trader.adapters.binance.common.schemas.account import BinanceOrder
from nautilus_trader.adapters.binance.common.schemas.account import BinanceStatusCode
from nautilus_trader.adapters.binance.common.symbol import BinanceSymbol
from nautilus_trader.adapters.binance.futures.enums import BinanceFuturesMarginType
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesAccountInfo
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesDualSidePosition
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesLeverage
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesMarginTypeResponse # fmt: skip
from nautilus_trader.adapters.binance.futures.schemas.account import BinanceFuturesPositionRisk
from nautilus_trader.adapters.binance.http.account import BinanceAccountHttpAPI
from nautilus_trader.adapters.binance.http.client import BinanceHttpClient
from nautilus_trader.adapters.binance.http.endpoint import BinanceHttpEndpoint
from nautilus_trader.adapters.binance.http.error import BinanceClientError
from nautilus_trader.common.component import LiveClock
from nautilus_trader.common.config import PositiveInt
from nautilus_trader.core.nautilus_pyo3 import HttpMethod
Expand Down Expand Up @@ -393,6 +396,64 @@ async def post(
return self._resp_decoder.decode(raw)


class BinanceFuturesMarginTypeHttp(BinanceHttpEndpoint):
"""
Margin type.

`POST /fapi/v1/marginType`

References
----------
https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Change-Margin-Type

"""

def __init__(
self,
client: BinanceHttpClient,
base_endpoint: str,
):
methods = {
HttpMethod.POST: BinanceSecurityType.TRADE,
}
url_path = base_endpoint + "marginType"
super().__init__(client, methods, url_path)
self._resp_decoder = msgspec.json.Decoder(BinanceFuturesMarginTypeResponse)

class PostParameters(msgspec.Struct, omit_defaults=True, frozen=True):
"""
Margin type POST endpoint parameters.

Parameters
----------
symbol : BinanceSymbol
marginType : str
ISOLATED or CROSSED
timestamp : str
The millisecond timestamp of the request.
recvWindow : str, optional
The response receive window in milliseconds for the request.

"""

symbol: BinanceSymbol
marginType: str
timestamp: str
recvWindow: str | None = None

async def post(
self,
params: PostParameters,
) -> BinanceFuturesMarginTypeResponse:
try:
raw = await self._method(HttpMethod.POST, params)
except BinanceClientError as e:
if e.message["msg"] == "No need to change margin type.":
return BinanceFuturesMarginTypeResponse(code=200, msg="success")
raise
return self._resp_decoder.decode(raw)


class BinanceFuturesAccountHttpAPI(BinanceAccountHttpAPI):
"""
Provides access to the Binance Futures Account/Trade HTTP REST API.
Expand Down Expand Up @@ -444,6 +505,10 @@ def __init__(
v2_endpoint_base,
)
self._endpoint_futures_leverage = BinanceFuturesLeverageHttp(client, self.base_endpoint)
self._endpoint_futures_margin_type = BinanceFuturesMarginTypeHttp(
client,
self.base_endpoint,
)

async def query_futures_hedge_mode(
self,
Expand Down Expand Up @@ -477,6 +542,30 @@ async def set_leverage(
),
)

async def set_margin_type(
self,
symbol: BinanceSymbol,
margin_type: BinanceFuturesMarginType,
recv_window: str | None = None,
) -> BinanceFuturesMarginTypeResponse:
"""
Change symbol level margin type.

:param symbol : BinanceSymbol
:param margin_type : BinanceFuturesMarginType
:param recv_window : str, optional
:return: BinanceFuturesMarginTypeResponse

"""
return await self._endpoint_futures_margin_type.post(
self._endpoint_futures_margin_type.PostParameters(
symbol=symbol,
marginType=margin_type.value,
timestamp=self._timestamp(),
recvWindow=recv_window,
),
)

async def set_futures_hedge_mode(
self,
dual_side_position: bool,
Expand Down
9 changes: 9 additions & 0 deletions nautilus_trader/adapters/binance/futures/schemas/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,12 @@ class BinanceFuturesLeverage(msgspec.Struct, frozen=True):
leverage: int
maxNotionalValue: str
symbol: str


class BinanceFuturesMarginTypeResponse(msgspec.Struct, frozen=True):
"""
HTTP response from Binance Futures `POST /fapi/v1/marginType`.
"""

code: int
msg: str
Loading