From 3833acf4860e76730e0235d9213d45b13db940f9 Mon Sep 17 00:00:00 2001 From: Gianluca Pagliara Date: Tue, 7 Jan 2025 14:49:34 +0100 Subject: [PATCH] refactor: Fix trading rules initialization for derivatives --- financepype/markets/market.py | 12 +++++++++ financepype/rules/trading_rule.py | 23 +++++++++++++++++ .../simulations/balances/engines/dashboard.py | 25 +++++++++++++------ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/financepype/markets/market.py b/financepype/markets/market.py index c3bdf4f..8cb518a 100644 --- a/financepype/markets/market.py +++ b/financepype/markets/market.py @@ -138,6 +138,10 @@ def validate_fields(self) -> Self: raise ValueError("Expiry date is required for futures") return self + @property + def is_spot(self) -> bool: + return self.instrument_type.is_spot + @property def is_derivative(self) -> bool: return self.instrument_type.is_derivative @@ -154,6 +158,14 @@ def is_future(self) -> bool: def is_option(self) -> bool: return self.instrument_type.is_option + @property + def is_linear(self) -> bool: + return self.instrument_type.is_linear + + @property + def is_inverse(self) -> bool: + return self.instrument_type.is_inverse + @classmethod def get_timeframe_type( cls, diff --git a/financepype/rules/trading_rule.py b/financepype/rules/trading_rule.py index 5d0e438..1655e3a 100644 --- a/financepype/rules/trading_rule.py +++ b/financepype/rules/trading_rule.py @@ -175,6 +175,29 @@ class DerivativeTradingRule(TradingRule): >>> print(future.perpetual) # True """ + @model_validator(mode="after") + def fix_collateral_tokens(self) -> Self: + """Set default collateral tokens if not specified. + + For linear instruments, uses quote currency as collateral + For inverse instruments, uses base currency as collateral + + Returns: + Self: The validated instance + """ + instrument_info = self.trading_pair.instrument_info + if instrument_info.is_linear: + if self.buy_order_collateral_token is None: + self.buy_order_collateral_token = instrument_info.quote + if self.sell_order_collateral_token is None: + self.sell_order_collateral_token = instrument_info.quote + elif instrument_info.is_inverse: + if self.buy_order_collateral_token is None: + self.buy_order_collateral_token = instrument_info.base + if self.sell_order_collateral_token is None: + self.sell_order_collateral_token = instrument_info.base + return self + @field_serializer("strike_price") def serialize_strike_price(self, strike_price: Decimal | None) -> str | None: return str(strike_price) if strike_price is not None else None diff --git a/financepype/simulations/balances/engines/dashboard.py b/financepype/simulations/balances/engines/dashboard.py index e24d38a..cc2e7d9 100644 --- a/financepype/simulations/balances/engines/dashboard.py +++ b/financepype/simulations/balances/engines/dashboard.py @@ -8,7 +8,7 @@ from financepype.operations.fees import OperationFee as Fee from financepype.operations.orders.models import OrderType, PositionAction, TradeType from financepype.platforms.platform import Platform -from financepype.rules.trading_rule import TradingRule +from financepype.rules.trading_rule import DerivativeTradingRule, TradingRule from financepype.simulations.balances.engines.models import AssetCashflow, OrderDetails from financepype.simulations.balances.engines.multiengine import BalanceMultiEngine @@ -29,13 +29,22 @@ def create_sample_order( trading_pair_obj = TradingPair(name=trading_pair) - trading_rule = TradingRule( - trading_pair=trading_pair_obj, - min_order_size=Decimal("0.0001"), - min_price_increment=Decimal("0.01"), - min_notional_size=Decimal("10"), - supports_market_orders=True, - ) + if trading_pair_obj.instrument_info.is_spot: + trading_rule = TradingRule( + trading_pair=trading_pair_obj, + min_order_size=Decimal("0.0001"), + min_price_increment=Decimal("0.01"), + min_notional_size=Decimal("10"), + supports_market_orders=True, + ) + else: + trading_rule = DerivativeTradingRule( + trading_pair=trading_pair_obj, + min_order_size=Decimal("0.0001"), + min_price_increment=Decimal("0.01"), + min_notional_size=Decimal("10"), + supports_market_orders=True, + ) return OrderDetails( platform=platform,