a
This commit is contained in:
parent
dee37d3c78
commit
b0e7ae8ef2
|
|
@ -114,6 +114,9 @@ INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `cate
|
|||
('TRAILING_STOP_ACTIVATION', '0.01', 'number', 'strategy', '移动止损激活阈值(盈利1%后激活)'),
|
||||
('TRAILING_STOP_PROTECT', '0.01', 'number', 'strategy', '移动止损保护利润(保护1%利润)'),
|
||||
|
||||
-- 持仓同步
|
||||
('POSITION_SYNC_INTERVAL', '300', 'number', 'scan', '持仓状态同步间隔(秒),默认5分钟,用于同步币安实际持仓与数据库状态'),
|
||||
|
||||
|
||||
-- API配置
|
||||
('BINANCE_API_KEY', '', 'string', 'api', '币安API密钥'),
|
||||
|
|
|
|||
|
|
@ -51,11 +51,13 @@ def init_configs():
|
|||
config_type = 'string'
|
||||
|
||||
# 确定分类
|
||||
if 'POSITION' in key:
|
||||
if key == 'TOP_N_SYMBOLS' or key == 'MAX_SCAN_SYMBOLS' or key == 'POSITION_SYNC_INTERVAL':
|
||||
category = 'scan'
|
||||
elif 'POSITION' in key and 'SYNC' not in key:
|
||||
category = 'position'
|
||||
elif 'RISK' in key or 'STOP' in key or 'PROFIT' in key:
|
||||
category = 'risk'
|
||||
elif 'SCAN' in key or 'INTERVAL' in key or 'VOLUME' in key or 'TOP_N_SYMBOLS' in key or 'MAX_SCAN_SYMBOLS' in key:
|
||||
elif 'SCAN' in key or 'INTERVAL' in key or 'VOLUME' in key:
|
||||
category = 'scan'
|
||||
else:
|
||||
category = 'strategy'
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ def _get_trading_config():
|
|||
'USE_TRAILING_STOP': True,
|
||||
'TRAILING_STOP_ACTIVATION': 0.01,
|
||||
'TRAILING_STOP_PROTECT': 0.01,
|
||||
'POSITION_SYNC_INTERVAL': 300, # 持仓状态同步间隔(秒),默认5分钟
|
||||
}
|
||||
|
||||
# 币安API配置(优先从数据库,回退到环境变量和默认值)
|
||||
|
|
|
|||
|
|
@ -653,6 +653,79 @@ class PositionManager:
|
|||
f"发现 {len(missing_in_db)} 个持仓在币安存在但数据库中没有记录: "
|
||||
f"{', '.join(missing_in_db)} (可能是手动开仓)"
|
||||
)
|
||||
|
||||
# 为手动开仓的持仓创建数据库记录并启动监控
|
||||
for symbol in missing_in_db:
|
||||
try:
|
||||
# 获取币安持仓详情
|
||||
binance_position = next(
|
||||
(p for p in binance_positions if p['symbol'] == symbol),
|
||||
None
|
||||
)
|
||||
if not binance_position:
|
||||
continue
|
||||
|
||||
position_amt = binance_position['positionAmt']
|
||||
entry_price = binance_position['entryPrice']
|
||||
quantity = abs(position_amt)
|
||||
side = 'BUY' if position_amt > 0 else 'SELL'
|
||||
|
||||
logger.info(
|
||||
f"{symbol} [状态同步] 检测到手动开仓,创建数据库记录... "
|
||||
f"({side} {quantity:.4f} @ {entry_price:.4f})"
|
||||
)
|
||||
|
||||
# 创建数据库记录
|
||||
trade_id = Trade.create(
|
||||
symbol=symbol,
|
||||
side=side,
|
||||
quantity=quantity,
|
||||
entry_price=entry_price,
|
||||
leverage=binance_position.get('leverage', 10),
|
||||
entry_reason='manual_entry' # 标记为手动开仓
|
||||
)
|
||||
|
||||
logger.info(f"{symbol} [状态同步] ✓ 数据库记录已创建 (ID: {trade_id})")
|
||||
|
||||
# 创建本地持仓记录(用于监控)
|
||||
ticker = await self.client.get_ticker_24h(symbol)
|
||||
current_price = ticker['price'] if ticker else entry_price
|
||||
|
||||
# 计算止损止盈
|
||||
stop_loss_price = self.risk_manager.get_stop_loss_price(entry_price, side)
|
||||
take_profit_price = self.risk_manager.get_take_profit_price(entry_price, side)
|
||||
|
||||
position_info = {
|
||||
'symbol': symbol,
|
||||
'side': side,
|
||||
'quantity': quantity,
|
||||
'entryPrice': entry_price,
|
||||
'changePercent': 0, # 手动开仓,无法计算涨跌幅
|
||||
'orderId': None,
|
||||
'tradeId': trade_id,
|
||||
'stopLoss': stop_loss_price,
|
||||
'takeProfit': take_profit_price,
|
||||
'initialStopLoss': stop_loss_price,
|
||||
'leverage': binance_position.get('leverage', 10),
|
||||
'entryReason': 'manual_entry',
|
||||
'atr': None,
|
||||
'maxProfit': 0.0,
|
||||
'trailingStopActivated': False
|
||||
}
|
||||
|
||||
self.active_positions[symbol] = position_info
|
||||
|
||||
# 启动WebSocket监控
|
||||
if self._monitoring_enabled:
|
||||
await self._start_position_monitoring(symbol)
|
||||
logger.info(f"{symbol} [状态同步] ✓ 已启动实时监控")
|
||||
|
||||
logger.info(f"{symbol} [状态同步] ✓ 手动开仓同步完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{symbol} [状态同步] ❌ 处理手动开仓失败: {e}")
|
||||
import traceback
|
||||
logger.error(f" 错误详情:\n{traceback.format_exc()}")
|
||||
|
||||
logger.info("持仓状态同步完成")
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class TradingStrategy:
|
|||
self.position_manager = position_manager
|
||||
self.running = False
|
||||
self._monitoring_started = False # 是否已启动监控
|
||||
self._sync_task = None # 定期同步任务
|
||||
|
||||
async def execute_strategy(self):
|
||||
"""
|
||||
|
|
@ -61,6 +62,10 @@ class TradingStrategy:
|
|||
except Exception as e:
|
||||
logger.warning(f"启动持仓监控失败: {e},将使用定时检查模式")
|
||||
|
||||
# 启动定期同步任务(独立于市场扫描)
|
||||
self._sync_task = asyncio.create_task(self._periodic_sync_positions())
|
||||
logger.info("定期持仓同步任务已启动")
|
||||
|
||||
try:
|
||||
while self.running:
|
||||
# 1. 扫描市场,找出涨跌幅最大的前N个货币对
|
||||
|
|
@ -216,6 +221,14 @@ class TradingStrategy:
|
|||
logger.error(f"策略执行出错: {e}", exc_info=True)
|
||||
finally:
|
||||
self.running = False
|
||||
# 停止定期同步任务
|
||||
if self._sync_task:
|
||||
self._sync_task.cancel()
|
||||
try:
|
||||
await self._sync_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
logger.info("定期持仓同步任务已停止")
|
||||
# 停止所有持仓的WebSocket监控
|
||||
try:
|
||||
await self.position_manager.stop_all_position_monitoring()
|
||||
|
|
@ -366,6 +379,31 @@ class TradingStrategy:
|
|||
'strength': signal_strength
|
||||
}
|
||||
|
||||
async def _periodic_sync_positions(self):
|
||||
"""
|
||||
定期同步币安持仓状态(独立任务,不依赖市场扫描)
|
||||
"""
|
||||
sync_interval = config.TRADING_CONFIG.get('POSITION_SYNC_INTERVAL', 300) # 默认5分钟
|
||||
logger.info(f"定期持仓同步任务启动,同步间隔: {sync_interval}秒")
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
await asyncio.sleep(sync_interval)
|
||||
|
||||
if not self.running:
|
||||
break
|
||||
|
||||
logger.debug("执行定期持仓状态同步...")
|
||||
await self.position_manager.sync_positions_with_binance()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
logger.info("定期持仓同步任务已取消")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"定期持仓同步任务出错: {e}")
|
||||
# 出错后等待一段时间再继续
|
||||
await asyncio.sleep(60)
|
||||
|
||||
def stop(self):
|
||||
"""停止策略"""
|
||||
self.running = False
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user