From 5d6ea67c71b45643eb7f067eeaf435df3096d823 Mon Sep 17 00:00:00 2001 From: lly835 Date: Sat, 8 Nov 2025 01:11:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=A4=E6=98=93=E5=AF=B9?= =?UTF-8?q?=E6=98=A0=E5=B0=84=20#=20Ticker=E6=98=A0=E5=B0=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=20(=E5=AF=B9=E5=86=B2=E6=A8=A1=E5=BC=8F=E4=B8=93?= =?UTF-8?q?=E7=94=A8)=20#=20=E7=94=A8=E4=BA=8E=E8=A7=A3=E5=86=B3=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E4=BA=A4=E6=98=93=E6=89=80=E4=BD=BF=E7=94=A8=E4=B8=8D?= =?UTF-8?q?=E5=90=8Cticker=E5=90=8D=E7=A7=B0=E7=9A=84=E9=97=AE=E9=A2=98=20?= =?UTF-8?q?#=20=E6=A0=BC=E5=BC=8F:=20{"=E6=BA=90=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E6=89=80=5Fto=5F=E7=9B=AE=E6=A0=87=E4=BA=A4=E6=98=93=E6=89=80"?= =?UTF-8?q?:=20{"=E6=BA=90ticker":=20"=E7=9B=AE=E6=A0=87ticker"}}=20#=20?= =?UTF-8?q?=E4=BE=8B=E5=AD=90:=20Extended=E4=BD=BF=E7=94=A8"EUR"=EF=BC=8CL?= =?UTF-8?q?ighter=E4=BD=BF=E7=94=A8"EURUSD"=20#=20=E6=B3=A8=E6=84=8F:=20li?= =?UTF-8?q?ghter=E4=B8=8A=E4=BA=A4=E6=98=93EUR=E8=A6=81=E4=BD=BF=E7=94=A8I?= =?UTF-8?q?solated=E4=BF=9D=E8=AF=81=E9=87=91=E6=A8=A1=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E8=AF=B7=E5=85=88=E6=89=8B=E5=8A=A8=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- env_example.txt | 7 +++++ exchanges/extended.py | 2 +- hedge/hedge_mode_ext.py | 61 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/env_example.txt b/env_example.txt index ea9a7e01..38e6ee50 100644 --- a/env_example.txt +++ b/env_example.txt @@ -62,6 +62,13 @@ LOG_FILE=trading_log.csv TIMEZONE=Asia/Shanghai +# Ticker映射配置 (对冲模式专用) +# 用于解决不同交易所使用不同ticker名称的问题 +# 格式: {"源交易所_to_目标交易所": {"源ticker": "目标ticker"}} +# 例子: Extended使用"EUR",Lighter使用"EURUSD" +# 注意: lighter上交易EUR要使用Isolated保证金模式,请先手动切换 +TICKER_MAPPING={"extended_to_lighter": {"EUR":"EURUSD","GBP":"GBPUSD","JPY":"JPYUSD","AUD":"AUDUSD"}, "backpack_to_lighter": {"EUR":"EURUSD"}, "grvt_to_lighter": {"EUR":"EURUSD"}} + # EdgeX API Endpoints EDGEX_BASE_URL=https://pro.edgex.exchange EDGEX_WS_URL=wss://quote.edgex.exchange \ No newline at end of file diff --git a/exchanges/extended.py b/exchanges/extended.py index c26ad0e0..903dfd04 100644 --- a/exchanges/extended.py +++ b/exchanges/extended.py @@ -13,7 +13,7 @@ from helpers.logger import TradingLogger from x10.perpetual.trading_client import PerpetualTradingClient -from x10.perpetual.configuration import STARKNET_MAINNET_CONFIG +from x10.perpetual.configuration import MAINNET_CONFIG as STARKNET_MAINNET_CONFIG from x10.perpetual.accounts import StarkPerpetualAccount from x10.perpetual.orders import TimeInForce, OrderSide diff --git a/hedge/hedge_mode_ext.py b/hedge/hedge_mode_ext.py index 29a4d9ff..c2a75596 100644 --- a/hedge/hedge_mode_ext.py +++ b/hedge/hedge_mode_ext.py @@ -147,6 +147,9 @@ def __init__(self, ticker: str, order_quantity: Decimal, fill_timeout: int = 5, self.extended_vault = os.getenv('EXTENDED_VAULT') self.extended_stark_key_private = os.getenv('EXTENDED_STARK_KEY_PRIVATE') self.extended_stark_key_public = os.getenv('EXTENDED_STARK_KEY_PUBLIC') + + # Load ticker mapping configuration + self._load_ticker_mapping() self.extended_api_key = os.getenv('EXTENDED_API_KEY') def shutdown(self, signum=None, frame=None): @@ -179,6 +182,52 @@ def shutdown(self, signum=None, frame=None): except Exception: pass + def _load_ticker_mapping(self): + """Load ticker mapping configuration from environment variables.""" + # Default fallback mapping for common currency pairs + default_mapping = { + "extended_to_lighter": { + "EUR": "EURUSD", + "GBP": "GBPUSD", + "JPY": "JPYUSD", + "AUD": "AUDUSD" + } + } + + try: + # Try to load from environment variable + ticker_mapping_str = os.getenv('TICKER_MAPPING') + + if ticker_mapping_str: + self.ticker_mapping = json.loads(ticker_mapping_str) + self.logger.info(f"✅ Loaded ticker mapping from .env: {self.ticker_mapping}") + else: + self.ticker_mapping = default_mapping + self.logger.info(f"⚠️ TICKER_MAPPING not found in .env, using default mapping: {default_mapping}") + + except json.JSONDecodeError as e: + self.ticker_mapping = default_mapping + self.logger.error(f"⚠️ Error parsing TICKER_MAPPING JSON: {e}, using default mapping: {default_mapping}") + except Exception as e: + self.ticker_mapping = default_mapping + self.logger.error(f"⚠️ Unexpected error loading ticker mapping: {e}, using default mapping: {default_mapping}") + + def get_lighter_ticker(self): + """Get the corresponding Lighter ticker for the current ticker.""" + mapping_key = "extended_to_lighter" + + # Check if mapping exists for this exchange combination + if mapping_key in self.ticker_mapping: + exchange_mapping = self.ticker_mapping[mapping_key] + if self.ticker in exchange_mapping: + lighter_ticker = exchange_mapping[self.ticker] + self.logger.info(f"🔄 Ticker mapping: Extended '{self.ticker}' → Lighter '{lighter_ticker}'") + return lighter_ticker + + # If no mapping found, use original ticker and log warning + self.logger.warning(f"⚠️ No ticker mapping found for Extended '{self.ticker}' to Lighter, using original ticker") + return self.ticker + def _initialize_csv_file(self): """Initialize CSV file with headers if it doesn't exist.""" if not os.path.exists(self.csv_filename): @@ -551,6 +600,9 @@ def get_lighter_market_config(self) -> Tuple[int, int, int, Decimal]: url = f"{self.lighter_base_url}/api/v1/orderBooks" headers = {"accept": "application/json"} + # Get the mapped ticker for Lighter + lighter_ticker = self.get_lighter_ticker() + try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() @@ -564,15 +616,16 @@ def get_lighter_market_config(self) -> Tuple[int, int, int, Decimal]: raise Exception("Unexpected response format") for market in data["order_books"]: - if market["symbol"] == self.ticker: + if market["symbol"] == lighter_ticker: price_multiplier = pow(10, market["supported_price_decimals"]) - return (market["market_id"], - pow(10, market["supported_size_decimals"]), + self.logger.info(f"✅ Found Lighter market config for {lighter_ticker}: market_id={market['market_id']}") + return (market["market_id"], + pow(10, market["supported_size_decimals"]), price_multiplier, Decimal("1") / (Decimal("10") ** market["supported_price_decimals"]) ) - raise Exception(f"Ticker {self.ticker} not found") + raise Exception(f"Ticker {lighter_ticker} not found") except Exception as e: self.logger.error(f"⚠️ Error getting market config: {e}")