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_ACTIVATION', '0.01', 'number', 'strategy', '移动止损激活阈值(盈利1%后激活)'),
|
||||||
('TRAILING_STOP_PROTECT', '0.01', 'number', 'strategy', '移动止损保护利润(保护1%利润)'),
|
('TRAILING_STOP_PROTECT', '0.01', 'number', 'strategy', '移动止损保护利润(保护1%利润)'),
|
||||||
|
|
||||||
|
-- 持仓同步
|
||||||
|
('POSITION_SYNC_INTERVAL', '300', 'number', 'scan', '持仓状态同步间隔(秒),默认5分钟,用于同步币安实际持仓与数据库状态'),
|
||||||
|
|
||||||
|
|
||||||
-- API配置
|
-- API配置
|
||||||
('BINANCE_API_KEY', '', 'string', 'api', '币安API密钥'),
|
('BINANCE_API_KEY', '', 'string', 'api', '币安API密钥'),
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,13 @@ def init_configs():
|
||||||
config_type = 'string'
|
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'
|
category = 'position'
|
||||||
elif 'RISK' in key or 'STOP' in key or 'PROFIT' in key:
|
elif 'RISK' in key or 'STOP' in key or 'PROFIT' in key:
|
||||||
category = 'risk'
|
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'
|
category = 'scan'
|
||||||
else:
|
else:
|
||||||
category = 'strategy'
|
category = 'strategy'
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ def _get_trading_config():
|
||||||
'USE_TRAILING_STOP': True,
|
'USE_TRAILING_STOP': True,
|
||||||
'TRAILING_STOP_ACTIVATION': 0.01,
|
'TRAILING_STOP_ACTIVATION': 0.01,
|
||||||
'TRAILING_STOP_PROTECT': 0.01,
|
'TRAILING_STOP_PROTECT': 0.01,
|
||||||
|
'POSITION_SYNC_INTERVAL': 300, # 持仓状态同步间隔(秒),默认5分钟
|
||||||
}
|
}
|
||||||
|
|
||||||
# 币安API配置(优先从数据库,回退到环境变量和默认值)
|
# 币安API配置(优先从数据库,回退到环境变量和默认值)
|
||||||
|
|
|
||||||
|
|
@ -654,6 +654,79 @@ class PositionManager:
|
||||||
f"{', '.join(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("持仓状态同步完成")
|
logger.info("持仓状态同步完成")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class TradingStrategy:
|
||||||
self.position_manager = position_manager
|
self.position_manager = position_manager
|
||||||
self.running = False
|
self.running = False
|
||||||
self._monitoring_started = False # 是否已启动监控
|
self._monitoring_started = False # 是否已启动监控
|
||||||
|
self._sync_task = None # 定期同步任务
|
||||||
|
|
||||||
async def execute_strategy(self):
|
async def execute_strategy(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -61,6 +62,10 @@ class TradingStrategy:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"启动持仓监控失败: {e},将使用定时检查模式")
|
logger.warning(f"启动持仓监控失败: {e},将使用定时检查模式")
|
||||||
|
|
||||||
|
# 启动定期同步任务(独立于市场扫描)
|
||||||
|
self._sync_task = asyncio.create_task(self._periodic_sync_positions())
|
||||||
|
logger.info("定期持仓同步任务已启动")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while self.running:
|
while self.running:
|
||||||
# 1. 扫描市场,找出涨跌幅最大的前N个货币对
|
# 1. 扫描市场,找出涨跌幅最大的前N个货币对
|
||||||
|
|
@ -216,6 +221,14 @@ class TradingStrategy:
|
||||||
logger.error(f"策略执行出错: {e}", exc_info=True)
|
logger.error(f"策略执行出错: {e}", exc_info=True)
|
||||||
finally:
|
finally:
|
||||||
self.running = False
|
self.running = False
|
||||||
|
# 停止定期同步任务
|
||||||
|
if self._sync_task:
|
||||||
|
self._sync_task.cancel()
|
||||||
|
try:
|
||||||
|
await self._sync_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
logger.info("定期持仓同步任务已停止")
|
||||||
# 停止所有持仓的WebSocket监控
|
# 停止所有持仓的WebSocket监控
|
||||||
try:
|
try:
|
||||||
await self.position_manager.stop_all_position_monitoring()
|
await self.position_manager.stop_all_position_monitoring()
|
||||||
|
|
@ -366,6 +379,31 @@ class TradingStrategy:
|
||||||
'strength': signal_strength
|
'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):
|
def stop(self):
|
||||||
"""停止策略"""
|
"""停止策略"""
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user