Files
crypto_monitor/strategy_trend_exchange.py
dekun 72f0090fb8 fix(trend): pass empty dict to ccxt create_order for DCA adds
Gate build_gate_order_params returns {} which is falsy; params or None broke trend_market_add with NoneType is not iterable while first-leg place_exchange_order worked.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 17:52:12 +08:00

98 lines
4.2 KiB
Python

"""趋势回调:各交易所止损刷新、市价加/平仓(通过 app 模块能力探测)。"""
from __future__ import annotations
import time
from typing import Any
def _m(cfg: dict) -> Any:
return cfg["app_module"]
def trend_refresh_stop_only(cfg: dict, exchange_symbol: str, direction: str, stop_loss: float) -> None:
m = _m(cfg)
if hasattr(m, "_gate_place_stop_loss_only_position"):
if hasattr(m, "cancel_gate_swap_trigger_orders"):
m.cancel_gate_swap_trigger_orders(exchange_symbol)
m._gate_place_stop_loss_only_position(exchange_symbol, direction, stop_loss)
return
if hasattr(m, "_binance_place_stop_loss_only"):
m._binance_place_stop_loss_only(exchange_symbol, direction, stop_loss)
return
if hasattr(m, "_okx_place_stop_loss_only"):
m._okx_place_stop_loss_only(exchange_symbol, direction, stop_loss)
return
raise RuntimeError("当前实例未配置趋势回调止损挂单能力")
def trend_market_add(cfg: dict, exchange_symbol: str, direction: str, contracts: float, leverage: int):
m = _m(cfg)
ex = m.exchange
m.ensure_markets_loaded()
ex.set_leverage(int(leverage), exchange_symbol)
side = "buy" if direction == "long" else "sell"
if hasattr(m, "build_gate_order_params"):
params = m.build_gate_order_params(direction, reduce_only=False)
elif hasattr(m, "build_binance_order_params"):
params = m.build_binance_order_params(direction, reduce_only=False)
elif hasattr(m, "build_okx_order_params"):
params = m.build_okx_order_params(direction, reduce_only=False)
else:
params = {}
order_params = params if params is not None else {}
return ex.create_order(exchange_symbol, "market", side, float(contracts), None, order_params)
def trend_market_close(cfg: dict, exchange_symbol: str, direction: str, pos_qty: float, leverage: int):
m = _m(cfg)
ex = m.exchange
m.ensure_markets_loaded()
ex.set_leverage(int(leverage), exchange_symbol)
side = "sell" if direction == "long" else "buy"
amt = float(ex.amount_to_precision(exchange_symbol, float(pos_qty)))
if hasattr(m, "close_exchange_order"):
row = {
"exchange_symbol": exchange_symbol,
"symbol": exchange_symbol,
"direction": direction,
"order_amount": amt,
}
return m.close_exchange_order(row)
if hasattr(m, "build_gate_order_params"):
params = m.build_gate_order_params(direction, reduce_only=True)
return ex.create_order(exchange_symbol, "market", side, amt, None, params)
if hasattr(m, "build_binance_order_params"):
for params in m._binance_market_close_param_candidates(direction):
try:
return ex.create_order(exchange_symbol, "market", side, amt, None, params)
except Exception as e:
if not m._is_binance_close_param_retryable(str(e)):
raise
raise RuntimeError("平仓失败")
if hasattr(m, "build_okx_order_params"):
params = m.build_okx_order_params(direction, reduce_only=True)
return ex.create_order(exchange_symbol, "market", side, amt, None, params)
return ex.create_order(exchange_symbol, "market", side, amt, None, {"reduceOnly": True})
def trend_replace_tpsl(cfg: dict, order_row: dict, stop_loss: float, take_profit: float) -> None:
"""趋势保本移交:先撤条件单再挂保本止损 + 计划止盈(与下单监控一致)。"""
m = _m(cfg)
fn = getattr(m, "replace_active_monitor_tpsl_on_exchange", None)
if not callable(fn):
raise RuntimeError("当前实例未配置止盈止损同步能力")
fn(order_row, float(stop_loss), float(take_profit))
def cancel_symbol_orders(cfg: dict, exchange_symbol: str) -> None:
m = _m(cfg)
if hasattr(m, "cancel_all_open_orders_for_symbol"):
m.cancel_all_open_orders_for_symbol(exchange_symbol)
return
if hasattr(m, "cancel_gate_swap_trigger_orders"):
m.cancel_gate_swap_trigger_orders(exchange_symbol)
if hasattr(m, "cancel_binance_futures_open_orders"):
m.cancel_binance_futures_open_orders(exchange_symbol)
if hasattr(m, "cancel_okx_swap_open_orders"):
m.cancel_okx_swap_open_orders(exchange_symbol)