|
@@ -41,10 +41,13 @@ class TradingStrategy:
|
|
|
"""初始化策略"""
|
|
"""初始化策略"""
|
|
|
self.state = StrategyState.WAITING_INIT
|
|
self.state = StrategyState.WAITING_INIT
|
|
|
self.current_position = None # 当前持仓信息
|
|
self.current_position = None # 当前持仓信息
|
|
|
- self.entry_price_bps = 5 # 入场时的价差
|
|
|
|
|
|
|
+ self.entry_price_bps = 5 # 入场时的价差(单位:bps)
|
|
|
self.target_symbol = "DOGE" # 目标交易对
|
|
self.target_symbol = "DOGE" # 目标交易对
|
|
|
|
|
+ self.trade_quantity = 1 # 交易数量(买卖数量)
|
|
|
self.account_info = None # 存储账户信息
|
|
self.account_info = None # 存储账户信息
|
|
|
self.last_account_update_time = 0 # 上次更新账户信息的时间戳
|
|
self.last_account_update_time = 0 # 上次更新账户信息的时间戳
|
|
|
|
|
+ self.last_trade_time = 0 # 上次交易时间戳(开仓或平仓)
|
|
|
|
|
+ self.position_side = None # 持仓方向:'long' 或 'short'
|
|
|
|
|
|
|
|
self.account_index = 318163
|
|
self.account_index = 318163
|
|
|
self.api_key_index = 0
|
|
self.api_key_index = 0
|
|
@@ -153,23 +156,194 @@ class TradingStrategy:
|
|
|
|
|
|
|
|
async def _handle_idle_monitoring(self, market_data):
|
|
async def _handle_idle_monitoring(self, market_data):
|
|
|
"""处理空闲监听状态 - 监控价差"""
|
|
"""处理空闲监听状态 - 监控价差"""
|
|
|
- # TODO: 实现价差监控逻辑
|
|
|
|
|
- pass
|
|
|
|
|
|
|
+ symbol = market_data.get('symbol')
|
|
|
|
|
+ if symbol != self.target_symbol:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ binance_price = market_data.get('binance_price')
|
|
|
|
|
+ lighter_price = market_data.get('lighter_price')
|
|
|
|
|
+ orderbook = market_data.get('orderbook')
|
|
|
|
|
+
|
|
|
|
|
+ if not binance_price or not lighter_price or not orderbook:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 计算价差(单位:bps)
|
|
|
|
|
+ binance_price_float = float(binance_price) if isinstance(binance_price, str) else binance_price
|
|
|
|
|
+ lighter_price_float = float(lighter_price) if isinstance(lighter_price, str) else lighter_price
|
|
|
|
|
+ price_diff_bps = (lighter_price_float - binance_price_float) / binance_price_float * 10000
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否触发开仓条件
|
|
|
|
|
+ if price_diff_bps > self.entry_price_bps:
|
|
|
|
|
+ # 做空:价差过大,lighter价格高于binance,卖出lighter
|
|
|
|
|
+ logger.info(f"触发做空条件:价差={price_diff_bps:.2f}bps > {self.entry_price_bps}bps")
|
|
|
|
|
+ await self._open_position(orderbook, binance_price_float, is_ask=True, side='short')
|
|
|
|
|
+ elif price_diff_bps < -self.entry_price_bps:
|
|
|
|
|
+ # 做多:价差过小(负值),lighter价格低于binance,买入lighter
|
|
|
|
|
+ logger.info(f"触发做多条件:价差={price_diff_bps:.2f}bps < -{self.entry_price_bps}bps")
|
|
|
|
|
+ await self._open_position(orderbook, binance_price_float, is_ask=False, side='long')
|
|
|
|
|
+
|
|
|
|
|
+ async def _open_position(self, orderbook, price, is_ask, side):
|
|
|
|
|
+ """开仓"""
|
|
|
|
|
+ logger.info(f"开始开仓:方向={'做空' if side == 'short' else '做多'},数量={self.trade_quantity},价格={price}")
|
|
|
|
|
+
|
|
|
|
|
+ tx_hash, error = await self.create_order_and_send_tx(
|
|
|
|
|
+ orderbook=orderbook,
|
|
|
|
|
+ quantity=self.trade_quantity,
|
|
|
|
|
+ price=price,
|
|
|
|
|
+ is_ask=is_ask,
|
|
|
|
|
+ reduce_only=False
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if error:
|
|
|
|
|
+ logger.error(f"开仓失败: {error}")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 记录开仓时间和持仓方向
|
|
|
|
|
+ self.last_trade_time = time.time()
|
|
|
|
|
+ self.position_side = side
|
|
|
|
|
+
|
|
|
|
|
+ # 转换状态到执行交易
|
|
|
|
|
+ self.state = StrategyState.EXECUTING_TRADE
|
|
|
|
|
+ logger.info(f"状态转换: IDLE_MONITORING -> EXECUTING_TRADE,交易哈希={tx_hash}")
|
|
|
|
|
+ logger.info(f"等待1秒后检查持仓...")
|
|
|
|
|
|
|
|
async def _handle_executing_trade(self, market_data):
|
|
async def _handle_executing_trade(self, market_data):
|
|
|
- """处理执行交易状态"""
|
|
|
|
|
- # TODO: 实现交易执行逻辑
|
|
|
|
|
- pass
|
|
|
|
|
|
|
+ """处理执行交易状态 - 等待1秒后检查持仓"""
|
|
|
|
|
+ # 检查是否已经等待了至少1秒
|
|
|
|
|
+ if time.time() - self.last_trade_time < 1.0:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 检查持仓
|
|
|
|
|
+ symbol = market_data.get('symbol')
|
|
|
|
|
+ if symbol != self.target_symbol:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ if not self.account_info or not self.account_info.accounts:
|
|
|
|
|
+ logger.warning("账户信息不可用,无法检查持仓")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 查找目标交易对的持仓
|
|
|
|
|
+ position = None
|
|
|
|
|
+ for pos in self.account_info.accounts[0].positions:
|
|
|
|
|
+ if pos.symbol == self.target_symbol:
|
|
|
|
|
+ position = pos
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if position and int(position.position) != 0:
|
|
|
|
|
+ # 有持仓,转换到等待价差回归状态
|
|
|
|
|
+ self.current_position = position
|
|
|
|
|
+ self.state = StrategyState.WAITING_CONVERGENCE
|
|
|
|
|
+ logger.info(f"检测到持仓:方向={'做多' if position.sign == 1 else '做空'},数量={position.position}")
|
|
|
|
|
+ logger.info(f"状态转换: EXECUTING_TRADE -> WAITING_CONVERGENCE")
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 没有持仓,回到空闲状态
|
|
|
|
|
+ logger.warning(f"开仓后未检测到持仓,回到空闲状态")
|
|
|
|
|
+ self.state = StrategyState.IDLE_MONITORING
|
|
|
|
|
+ self.position_side = None
|
|
|
|
|
+ logger.info(f"状态转换: EXECUTING_TRADE -> IDLE_MONITORING")
|
|
|
|
|
|
|
|
async def _handle_waiting_convergence(self, market_data):
|
|
async def _handle_waiting_convergence(self, market_data):
|
|
|
- """处理等待收敛状态"""
|
|
|
|
|
- # TODO: 实现等待价差收敛逻辑
|
|
|
|
|
- pass
|
|
|
|
|
|
|
+ """处理等待收敛状态 - 等待价差回归到0轴"""
|
|
|
|
|
+ symbol = market_data.get('symbol')
|
|
|
|
|
+ if symbol != self.target_symbol:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ binance_price = market_data.get('binance_price')
|
|
|
|
|
+ lighter_price = market_data.get('lighter_price')
|
|
|
|
|
+ orderbook = market_data.get('orderbook')
|
|
|
|
|
+
|
|
|
|
|
+ if not binance_price or not lighter_price or not orderbook:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 计算价差(单位:bps)
|
|
|
|
|
+ binance_price_float = float(binance_price) if isinstance(binance_price, str) else binance_price
|
|
|
|
|
+ lighter_price_float = float(lighter_price) if isinstance(lighter_price, str) else lighter_price
|
|
|
|
|
+ price_diff_bps = (lighter_price_float - binance_price_float) / binance_price_float * 10000
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否触发平仓条件
|
|
|
|
|
+ should_close = False
|
|
|
|
|
+ if self.position_side == 'long':
|
|
|
|
|
+ # 做多:价差需要往上回归(从负值回到0或正值)
|
|
|
|
|
+ if price_diff_bps >= 0:
|
|
|
|
|
+ should_close = True
|
|
|
|
|
+ logger.info(f"做多平仓条件触发:价差={price_diff_bps:.2f}bps >= 0")
|
|
|
|
|
+ elif self.position_side == 'short':
|
|
|
|
|
+ # 做空:价差需要往下回归(从正值回到0或负值)
|
|
|
|
|
+ if price_diff_bps <= 0:
|
|
|
|
|
+ should_close = True
|
|
|
|
|
+ logger.info(f"做空平仓条件触发:价差={price_diff_bps:.2f}bps <= 0")
|
|
|
|
|
+
|
|
|
|
|
+ if should_close:
|
|
|
|
|
+ await self._close_position(orderbook, binance_price_float, lighter_price_float)
|
|
|
|
|
+
|
|
|
|
|
+ async def _close_position(self, orderbook, binance_price, lighter_price):
|
|
|
|
|
+ """平仓"""
|
|
|
|
|
+ # 确定平仓价格:使用不利方向的价格
|
|
|
|
|
+ if self.position_side == 'short':
|
|
|
|
|
+ # 做空平仓(买入):取两者较高的价格
|
|
|
|
|
+ close_price = max(binance_price, lighter_price)
|
|
|
|
|
+ is_ask = False # 买入
|
|
|
|
|
+ else: # long
|
|
|
|
|
+ # 做多平仓(卖出):取两者较低的价格
|
|
|
|
|
+ close_price = min(binance_price, lighter_price)
|
|
|
|
|
+ is_ask = True # 卖出
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(f"开始平仓:方向={'做空' if self.position_side == 'short' else '做多'},价格={close_price}")
|
|
|
|
|
+
|
|
|
|
|
+ tx_hash, error = await self.create_order_and_send_tx(
|
|
|
|
|
+ orderbook=orderbook,
|
|
|
|
|
+ quantity=self.trade_quantity,
|
|
|
|
|
+ price=close_price,
|
|
|
|
|
+ is_ask=is_ask,
|
|
|
|
|
+ reduce_only=True
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if error:
|
|
|
|
|
+ logger.error(f"平仓失败: {error}")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 记录平仓时间
|
|
|
|
|
+ self.last_trade_time = time.time()
|
|
|
|
|
+
|
|
|
|
|
+ # 转换状态到平仓中
|
|
|
|
|
+ self.state = StrategyState.CLOSING_POSITION
|
|
|
|
|
+ logger.info(f"状态转换: WAITING_CONVERGENCE -> CLOSING_POSITION,交易哈希={tx_hash}")
|
|
|
|
|
+ logger.info(f"等待1秒后检查平仓是否生效...")
|
|
|
|
|
|
|
|
async def _handle_closing_position(self, market_data):
|
|
async def _handle_closing_position(self, market_data):
|
|
|
- """处理平仓状态"""
|
|
|
|
|
- # TODO: 实现平仓逻辑
|
|
|
|
|
- pass
|
|
|
|
|
|
|
+ """处理平仓中状态 - 等待1秒后检查持仓是否为0"""
|
|
|
|
|
+ # 检查是否已经等待了至少1秒
|
|
|
|
|
+ if time.time() - self.last_trade_time < 1.0:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 检查持仓
|
|
|
|
|
+ symbol = market_data.get('symbol')
|
|
|
|
|
+ if symbol != self.target_symbol:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ if not self.account_info or not self.account_info.accounts:
|
|
|
|
|
+ logger.warning("账户信息不可用,无法检查平仓状态")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # 查找目标交易对的持仓
|
|
|
|
|
+ position = None
|
|
|
|
|
+ for pos in self.account_info.accounts[0].positions:
|
|
|
|
|
+ if pos.symbol == self.target_symbol:
|
|
|
|
|
+ position = pos
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if not position or int(position.position) == 0:
|
|
|
|
|
+ # 平仓成功,回到空闲状态
|
|
|
|
|
+ logger.info(f"平仓成功,当前持仓为0")
|
|
|
|
|
+ self.state = StrategyState.IDLE_MONITORING
|
|
|
|
|
+ self.position_side = None
|
|
|
|
|
+ self.current_position = None
|
|
|
|
|
+ logger.info(f"状态转换: CLOSING_POSITION -> IDLE_MONITORING")
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 平仓未生效,回到执行交易状态重新检查
|
|
|
|
|
+ logger.warning(f"平仓未生效,当前持仓={position.position},重新检查持仓状态")
|
|
|
|
|
+ self.state = StrategyState.EXECUTING_TRADE
|
|
|
|
|
+ logger.info(f"状态转换: CLOSING_POSITION -> EXECUTING_TRADE")
|
|
|
|
|
|
|
|
async def _handle_position_closed(self):
|
|
async def _handle_position_closed(self):
|
|
|
"""处理平仓完成状态"""
|
|
"""处理平仓完成状态"""
|