本文给出 3 种移动止盈止损风控模型:点数 / 价格比例 / 盈亏比例,包括固定止损 + 移动止盈,移动止盈指达到激活条件后启动,发生回撤设定条件后平仓,可直接挂载到任意已有策略上作为风控层。
概述
移动止盈止损:包括固定止损 + 移动止盈。移动止盈指达到设置的激活条件后启动,发生回撤设定条件后进行平仓。
3 个模型共享相同的架构:
| 函数 | 作用 |
|---|---|
on_init |
初始化计数器 counter、处理标志 processing,额外初始化极值跟踪变量 |
on_tick |
每 4 个 tick 触发一次 auto_tpsl,避免过于频繁 |
close_order |
根据 send_order_mode(市价/现价/对价)确定平仓价格并发单,区分平今/平昨 |
auto_tpsl |
核心逻辑:遍历持仓 → 过滤挂载合约 → 计算盈亏 → 更新极值 → 判断激活/回撤 → 平今平昨分别下单 |
报单方式
send_order_mode 支持三种平仓报价方式:
| 方式 | 多头卖平取价 | 空头买平取价 |
|---|---|---|
| 市价 | UpperLimitPrice(涨停价) |
LowerLimitPrice(跌停价) |
| 现价 | LastPrice(最新价) |
LastPrice(最新价) |
| 对价 | BidPrice1(买一) |
AskPrice1(卖一) |
平今平昨处理
上期所(SHFE)/ 能源中心(INE)需要区分平今(comboffsetflag=3)与平昨(comboffsetflag=1);其他交易所合并为昨仓处理。
移动止盈三要素
- 激活条件:盈利达到启动阈值(
tp_start_points/tp_start_rate)后激活移动止盈 - 极值跟踪:记录持仓以来的最高价(多头)/ 最低价(空头)/ 最高盈亏比例
- 回撤触发:从极值回撤达到设定阈值(
tp_points/tp_rate)后平仓
一、移动止盈止损_点数
固定止损 + 移动止盈。盈利达
tp_start_points激活移动止盈,价格从极值回撤tp_points后平仓。
# ------------------------------------------#
# 文件类型:量化策略
# 帮助文档:https://jukequant.com/knowledge/category/strategy
# 期魔方,为您提供专业的量化服务
# ------------------------------------------#
from pydantic import BaseModel, Field
class Params(BaseModel, validate_assignment=True):
tp_start_points: float = Field(default=5, title="移动止盈启动点数")
tp_points: float = Field(default=2, title="移动止盈回撤点数")
sl_points: float = Field(default=2, title="固定止损点数")
send_order_mode: dict = Field(default={"options": ["市价", "现价", "对价"], "value": "市价"}, title="报单方式")
def on_init(context):
put_log("移动止盈止损(点数)风控模块(版本2025_09_04 17:30)启动", level="USER_LOG")
context.counter = 0
context.processing = False
context.highest_price = 0
context.lowest_price = float("inf")
context.trailing_activated_points = False
def on_tick(context):
if not context.processing:
context.processing = True
context.counter += 1
if context.counter >= 4:
auto_tpsl(context)
context.counter = 0
context.processing = False
def close_order(context, symbol, exchangeid, direction, volume, comboffsetflag):
"""
发送平仓订单:根据报单方式确定价格并下单
symbol: 合约代码
exchangeid: 交易所代码
direction: 平仓方向 0=买平,1=卖平
volume: 平仓手数
comboffsetflag: 平仓标志 1=平昨,3=平今
"""
try:
tick = get_tick(symbol)
if not tick.get("ActionDay"):
put_log(f"{symbol}的tick获取失败,等待下一次运行", level="USER_LOG")
return 0
price_field = ""
if context.send_order_mode["value"] == "市价":
price_field = "UpperLimitPrice" if direction == "0" else "LowerLimitPrice"
if context.send_order_mode["value"] == "现价":
price_field = "LastPrice" if direction == "0" else "LastPrice"
if context.send_order_mode["value"] == "对价":
price_field = "BidPrice1" if direction == "0" else "AskPrice1"
price = float(tick.get(price_field))
order = {
"symbol": symbol,
"exchangeid": exchangeid,
"limitprice": price,
"direction": direction,
"orderpricetype": "2",
"comboffsetflag": comboffsetflag,
"volumn": volume,
}
send_order(order)
except Exception as e:
print(f"平仓出错: {e}")
return 0
return 1
def auto_tpsl(context):
"""核心止盈止损逻辑:固定止损 + 移动止盈"""
position = get_position()
put_log("检测当前持仓", level="USER_LOG")
if position is not None:
CLOSE_DIRECTION_MAP = {"2": "1", "3": "0"}
for item in position:
InstrumentID = item.get("InstrumentID")
# 获取挂载合约ID,并进行过滤
mounted_instrument = BASE_SETTING.get("Instrument")
# 如果当前持仓不是挂载合约,则跳过这个持仓
if not mounted_instrument or InstrumentID != mounted_instrument:
continue
# 订阅行情
if InstrumentID not in BASE_SETTING["sub_Instruments"]:
put_log(f"订阅{InstrumentID}", level="USER_LOG")
put_log(BASE_SETTING["sub_Instruments"], level="USER_LOG")
register_futures_for_quotes(InstrumentID, "M1")
# 获取行情
tick = get_tick(InstrumentID)
if not tick.get("ActionDay"):
put_log(f"{InstrumentID}的tick获取失败,等待下一次运行", level="USER_LOG")
continue
# 持仓信息处理
info = item["symbolinfo"]
VolumeMultiple = info["VolumeMultiple"]
last_price = float(tick["LastPrice"])
PosiDirection = item["PosiDirection"]
open_price = item["OpenCost"] / VolumeMultiple / item["Position"]
# 更新价格极值
if VolumeMultiple > 0:
if PosiDirection == "2":
if last_price > context.highest_price:
context.highest_price = last_price
put_log(f"{InstrumentID}多方向最高价更新为{last_price}", level="USER_LOG")
else:
if last_price < context.lowest_price:
context.lowest_price = last_price
put_log(f"{InstrumentID}空方向最低价更新为{last_price}", level="USER_LOG")
# 计算盈亏
if PosiDirection == "2":
profit_points = last_price - open_price
loss_points = open_price - last_price
else:
profit_points = open_price - last_price
loss_points = last_price - open_price
# 计算点数
fixed_stop_loss_points = context.sl_points # 固定止损
trailing_take_profit_points = context.tp_points # 移动止盈
trailing_activation_points = context.tp_start_points # 移动止盈激活
# 检查是否激活移动止盈
if (
not context.trailing_activated_points
and profit_points >= trailing_activation_points
and not context.trailing_activated_points
):
context.trailing_activated_points = True
put_log(f"{InstrumentID}激活移动止盈:盈利点数{profit_points:.1f}", level="USER_LOG")
# 止损条件计算
loss_condition = fixed_stop_loss_points > 0 and loss_points >= fixed_stop_loss_points
# 止盈条件计算
profit_condition = False
if context.trailing_activated_points:
if PosiDirection == "2": # 多头
trailing_price = context.highest_price - trailing_take_profit_points
current_high = context.highest_price
profit_condition = last_price <= trailing_price
else: # 空头
trailing_price = context.lowest_price + trailing_take_profit_points
current_low = context.lowest_price
profit_condition = last_price >= trailing_price
# 触发平仓逻辑
if profit_condition or loss_condition:
direction = CLOSE_DIRECTION_MAP[PosiDirection]
exchangeid = item["ExchangeID"]
YdStrikeFrozen = item.get("YdStrikeFrozen") # 执行昨仓冻结
LongFrozen = item.get("LongFrozen") # 多头冻结
ShortFrozen = item.get("ShortFrozen") # 空头冻结
Frozen = LongFrozen if direction == "1" else ShortFrozen # 选择冻结方向
todayFrozen = Frozen - YdStrikeFrozen # 今日冻结 = 方向冻结 - 昨仓冻结
today_volume = item.get("TodayPosition") - todayFrozen # 今日可平仓 = 今日持仓 - 今日冻结
yestoday_volume = item.get("YdPosition") - YdStrikeFrozen # 昨仓可平仓 = 昨仓持仓 - 昨仓冻结
today_position = 0
context.highest_price = 0
context.lowest_price = float("inf")
context.trailing_activated_points = False
# 计算可平仓位
if exchangeid in ("SHFE", "INE"):
today_position = today_volume
yestoday_position = yestoday_volume
else:
yestoday_position = today_volume + yestoday_volume
# 发送平仓指令
if today_position > 0:
close_order(context, InstrumentID, exchangeid, direction, today_position, "3")
if yestoday_position > 0:
close_order(context, InstrumentID, exchangeid, direction, yestoday_position, "1")
# 记录日志
log_msg = f"{InstrumentID}触发{'止盈' if profit_condition else '止损'} "
if profit_condition:
if PosiDirection == "2":
drawdown = current_high - last_price
log_msg += f"当前价格:{last_price:.2f} 最高价:{current_high:.2f} 回撤点数:{drawdown:.2f}"
else:
drawdown = last_price - current_low
log_msg += f"当前价格:{last_price:.2f} 最低价:{current_low:.2f} 回撤点数:{drawdown:.2f}"
else:
fixed_stop_loss_points = loss_points
log_msg += f"现价:{last_price:.2f} 开仓价:{open_price} 止损点数:{fixed_stop_loss_points:.2f}"
put_log(log_msg, level="USER_LOG")
else:
put_log("持仓获取失败", level="USER_LOG")
def on_stop(context):
print("移动止盈止损(点数)风控模块")
二、移动止盈止损_价格比例
以价格比例作为触发条件。使用
trailing_highs字典按合约_方向键记录每个持仓的极值,支持多持仓独立跟踪。
# ------------------------------------------#
# 文件类型:量化策略
# 帮助文档:https://jukequant.com/knowledge/category/strategy
# 期魔方,为您提供专业的量化服务
# ------------------------------------------#
from pydantic import BaseModel, Field
class Params(BaseModel, validate_assignment=True):
tp_start_rate: float = Field(default=5, title="移动止盈启动比例(%)")
tp_rate: float = Field(default=2, title="移动止盈回撤比例(%)")
sl_rate: float = Field(default=2, title="固定止损比例(%)")
send_order_mode: dict = Field(default={"options": ["市价", "现价", "对价"], "value": "市价"}, title="报单方式")
def on_init(context):
put_log("移动止盈止损(价格比例)风控模块(版本2025_09_10 10:00)启动", level="USER_LOG")
context.trailing_highs = {} # 记录持仓最高价/最低价
context.counter = 0
context.processing = False
def on_tick(context):
if not context.processing:
context.processing = True
context.counter += 1
if context.counter >= 4:
auto_tpsl(context)
context.counter = 0
context.processing = False
def close_order(context, symbol, exchangeid, direction, volume, comboffsetflag):
"""
发送平仓订单:根据报单方式确定价格并下单
symbol: 合约代码
exchangeid: 交易所代码
direction: 平仓方向 0=买平,1=卖平
volume: 平仓手数
comboffsetflag: 平仓标志 1=平昨,3=平今
"""
try:
tick = get_tick(symbol)
if not tick.get("ActionDay"):
put_log(f"{symbol}的tick获取失败,等待下一次运行", level="USER_LOG")
return 0
price_field = ""
if context.send_order_mode["value"] == "市价":
price_field = "UpperLimitPrice" if direction == "0" else "LowerLimitPrice"
if context.send_order_mode["value"] == "现价":
price_field = "LastPrice" if direction == "0" else "LastPrice"
if context.send_order_mode["value"] == "对价":
price_field = "BidPrice1" if direction == "0" else "AskPrice1"
price = float(tick.get(price_field))
order = {
"symbol": symbol,
"exchangeid": exchangeid,
"limitprice": price,
"direction": direction,
"orderpricetype": "2",
"comboffsetflag": comboffsetflag,
"volumn": volume,
}
send_order(order)
except Exception as e:
print(f"平仓出错: {e}")
return 0
return 1
def auto_tpsl(context):
"""核心止盈止损逻辑:固定止损 + 移动止盈"""
position = get_position()
put_log("检测当前持仓", level="USER_LOG")
if position is not None:
CLOSE_DIRECTION_MAP = {"2": "1", "3": "0"}
# 清理已平仓的跟踪记录
current_keys = set()
for item in position:
key = f"{item['InstrumentID']}_{item['PosiDirection']}"
current_keys.add(key)
for key in list(context.trailing_highs.keys()):
if key not in current_keys:
del context.trailing_highs[key]
for item in position:
InstrumentID = item.get("InstrumentID")
# 获取挂载合约ID,并进行过滤
mounted_instrument = BASE_SETTING.get("Instrument")
# 如果当前持仓不是挂载合约,则跳过这个持仓
if not mounted_instrument or InstrumentID != mounted_instrument:
continue
# 订阅行情
if InstrumentID not in BASE_SETTING["sub_Instruments"]:
put_log(f"订阅{InstrumentID}", level="USER_LOG")
put_log(BASE_SETTING["sub_Instruments"], level="USER_LOG")
register_futures_for_quotes(InstrumentID, "M1")
# 获取行情
tick = get_tick(InstrumentID)
if not tick.get("ActionDay"):
put_log(f"{InstrumentID}的tick获取失败,等待下一次运行", level="USER_LOG")
continue
# 持仓信息处理
info = item["symbolinfo"]
VolumeMultiple = info["VolumeMultiple"]
last_price = float(tick["LastPrice"])
PosiDirection = item["PosiDirection"]
open_price = item["OpenCost"] / VolumeMultiple / item["Position"]
key = f"{InstrumentID}_{PosiDirection}"
# 止损条件计算
if PosiDirection == "2": # 多头
sl_price = open_price * (1 - context.sl_rate / 100)
loss_condition = last_price <= sl_price
else: # 空头
sl_price = open_price * (1 + context.sl_rate / 100)
loss_condition = last_price >= sl_price
# 止盈条件计算
profit_condition = False
if PosiDirection == "2": # 多头
if key in context.trailing_highs:
context.trailing_highs[key] = max(context.trailing_highs[key], last_price)
current_high = context.trailing_highs[key]
profit_condition = last_price <= current_high * (1 - context.tp_rate / 100)
else:
if last_price >= open_price * (1 + context.tp_start_rate / 100):
context.trailing_highs[key] = last_price
put_log(f"{InstrumentID}多方向盈利部分超过启动比例,开始记录回撤比例", level="USER_LOG")
else: # 空头
if key in context.trailing_highs:
context.trailing_highs[key] = min(context.trailing_highs[key], last_price)
current_low = context.trailing_highs[key]
profit_condition = last_price >= current_low * (1 + context.tp_rate / 100)
else:
if last_price <= open_price * (1 - context.tp_start_rate / 100):
context.trailing_highs[key] = last_price
put_log(f"{InstrumentID}空方向盈利部分超过启动比例,开始记录回撤比例", level="USER_LOG")
# 触发平仓逻辑
if profit_condition or loss_condition:
direction = CLOSE_DIRECTION_MAP[PosiDirection]
exchangeid = item["ExchangeID"]
YdStrikeFrozen = item.get("YdStrikeFrozen") # 执行昨仓冻结
LongFrozen = item.get("LongFrozen") # 多头冻结
ShortFrozen = item.get("ShortFrozen") # 空头冻结
Frozen = LongFrozen if direction == "1" else ShortFrozen # 选择冻结方向
todayFrozen = Frozen - YdStrikeFrozen # 今日冻结 = 方向冻结 - 昨仓冻结
today_volume = item.get("TodayPosition") - todayFrozen # 今日可平仓 = 今日持仓 - 今日冻结
yestoday_volume = item.get("YdPosition") - YdStrikeFrozen # 昨仓可平仓 = 昨仓持仓 - 昨仓冻结
today_position = 0
# 计算可平仓位
if exchangeid in ("SHFE", "INE"):
today_position = today_volume
yestoday_position = yestoday_volume
else:
yestoday_position = today_volume + yestoday_volume
# 发送平仓指令
if today_position > 0:
close_order(context, InstrumentID, exchangeid, direction, today_position, "3")
if yestoday_position > 0:
close_order(context, InstrumentID, exchangeid, direction, yestoday_position, "1")
# 记录日志
log_msg = f"{InstrumentID}触发{'止盈' if profit_condition else '止损'} "
if profit_condition:
if PosiDirection == "2":
current_high = context.trailing_highs.get(key, last_price)
drawdown = (current_high - last_price) / current_high * 100
log_msg += f"最高价:{current_high:.2f} 回撤:{drawdown:.2f}%"
else:
current_low = context.trailing_highs.get(key, last_price)
drawdown = (last_price - current_low) / current_low * 100
log_msg += f"最低价:{current_low:.2f} 回撤:{drawdown:.2f}%"
else:
log_msg += f"现价:{last_price:.2f} 止损价格:{sl_price:.2f}"
put_log(log_msg, level="USER_LOG")
else:
put_log("持仓获取失败", level="USER_LOG")
def on_stop(context):
print("移动止盈止损(价格比例)停止")
三、移动止盈止损_盈亏比例
以保证金比例作为触发条件。跟踪最高盈亏比例,回撤达
tp_rate后平仓。需调用get_symbolinfo获取margin_ratio。
# ------------------------------------------#
# 文件类型:量化策略
# 帮助文档:https://jukequant.com/knowledge/category/strategy
# 期魔方,为您提供专业的量化服务
# ------------------------------------------#
from pydantic import BaseModel, Field
class Params(BaseModel, validate_assignment=True):
tp_start_rate: float = Field(default=5, title="移动止盈启动保证金比例(%)")
tp_rate: float = Field(default=2, title="移动止盈回撤保证金比例(%)")
sl_rate: float = Field(default=2, title="固定止损保证金比例(%)")
send_order_mode: dict = Field(default={"options": ["市价", "现价", "对价"], "value": "市价"}, title="报单方式")
def on_init(context):
put_log("移动止盈止损(盈亏比例)风控模块(版本2025_09_04 9:00)启动", level="USER_LOG")
context.counter = 0
context.processing = False
context.trailing_activated = False
context.highest_profit_ratio = 0
def on_tick(context):
if not context.processing:
context.processing = True
context.counter += 1
if context.counter >= 4:
auto_tpsl(context)
context.counter = 0
context.processing = False
def close_order(context, symbol, exchangeid, direction, volume, comboffsetflag):
"""
发送平仓订单:根据报单方式确定价格并下单
symbol: 合约代码
exchangeid: 交易所代码
direction: 平仓方向 0=买平,1=卖平
volume: 平仓手数
comboffsetflag: 平仓标志 1=平昨,3=平今
"""
try:
tick = get_tick(symbol)
if not tick.get("ActionDay"):
put_log(f"{symbol}的tick获取失败,等待下一次运行", level="USER_LOG")
return 0
price_field = ""
if context.send_order_mode["value"] == "市价":
price_field = "UpperLimitPrice" if direction == "0" else "LowerLimitPrice"
if context.send_order_mode["value"] == "现价":
price_field = "LastPrice" if direction == "0" else "LastPrice"
if context.send_order_mode["value"] == "对价":
price_field = "BidPrice1" if direction == "0" else "AskPrice1"
price = float(tick.get(price_field))
order = {
"symbol": symbol,
"exchangeid": exchangeid,
"limitprice": price,
"direction": direction,
"orderpricetype": "2",
"comboffsetflag": comboffsetflag,
"volumn": volume,
}
send_order(order)
except Exception as e:
print(f"平仓出错: {e}")
return 0
return 1
def auto_tpsl(context):
"""核心止盈止损逻辑:固定止损 + 移动止盈"""
position = get_position()
put_log("检测当前持仓", level="USER_LOG")
if position is not None:
CLOSE_DIRECTION_MAP = {"2": "1", "3": "0"}
for item in position:
InstrumentID = item.get("InstrumentID")
# 获取挂载合约ID,并进行过滤
mounted_instrument = BASE_SETTING.get("Instrument")
# 如果当前持仓不是挂载合约,则跳过这个持仓
if not mounted_instrument or InstrumentID != mounted_instrument:
continue
# 订阅行情
if InstrumentID not in BASE_SETTING["sub_Instruments"]:
put_log(f"订阅{InstrumentID}", level="USER_LOG")
put_log(BASE_SETTING["sub_Instruments"], level="USER_LOG")
register_futures_for_quotes(InstrumentID, "M1")
# 获取行情
tick = get_tick(InstrumentID)
symbolinfo = get_symbolinfo(InstrumentID)
if not tick.get("ActionDay"):
put_log(f"{InstrumentID}的tick获取失败,等待下一次运行", level="USER_LOG")
continue
# 持仓信息处理
info = item["symbolinfo"]
VolumeMultiple = info["VolumeMultiple"]
last_price = float(tick["LastPrice"])
Position = item.get("Position")
PosiDirection = item["PosiDirection"]
open_price = item["OpenCost"] / VolumeMultiple / item["Position"]
margin_ratio = symbolinfo.get("margin_ratio") # 保证金
# 计算逐笔盈亏
if PosiDirection == "2":
profit = (last_price - open_price) * Position * VolumeMultiple
else:
profit = (open_price - last_price) * Position * VolumeMultiple
# 计算保证金
margin = open_price * VolumeMultiple * Position * margin_ratio
# 计算盈亏比例(基于保证金)
if margin_ratio > 0:
profit_ratio = (profit / margin) * 100
loss_ratio = (-profit / margin) * 100
else:
profit_ratio = 0.0
loss_ratio = 0.0
# 更新最高盈亏比例
if profit_ratio > context.highest_profit_ratio:
context.highest_profit_ratio = profit_ratio
put_log(f"{InstrumentID}最高盈利比例更新为{context.highest_profit_ratio:.2f}", level="USER_LOG")
# 止损条件计算
loss_condition = loss_ratio >= context.sl_rate
# 止盈条件计算
profit_condition = False
# 检查是否激活移动止盈
if profit_ratio >= context.tp_start_rate and not context.trailing_activated:
context.trailing_activated = True
put_log(f"{InstrumentID}激活移动止盈(盈亏比例):盈亏比例{profit_ratio:.2f}%", level="USER_LOG")
if context.trailing_activated:
current_drawdown = context.highest_profit_ratio - profit_ratio
profit_condition = current_drawdown >= context.tp_rate
# 触发平仓逻辑
if profit_condition or loss_condition:
direction = CLOSE_DIRECTION_MAP[PosiDirection]
exchangeid = item["ExchangeID"]
YdStrikeFrozen = item.get("YdStrikeFrozen") # 执行昨仓冻结
LongFrozen = item.get("LongFrozen") # 多头冻结
ShortFrozen = item.get("ShortFrozen") # 空头冻结
Frozen = LongFrozen if direction == "1" else ShortFrozen # 选择冻结方向
todayFrozen = Frozen - YdStrikeFrozen # 今日冻结 = 方向冻结 - 昨仓冻结
today_volume = item.get("TodayPosition") - todayFrozen # 今日可平仓 = 今日持仓 - 今日冻结
yestoday_volume = item.get("YdPosition") - YdStrikeFrozen # 昨仓可平仓 = 昨仓持仓 - 昨仓冻结
today_position = 0
context.trailing_activated = False
context.highest_profit_ratio = 0.0
# 计算可平仓位
if exchangeid in ("SHFE", "INE"):
today_position = today_volume
yestoday_position = yestoday_volume
else:
yestoday_position = today_volume + yestoday_volume
# 发送平仓指令
if today_position > 0:
close_order(context, InstrumentID, exchangeid, direction, today_position, "3")
if yestoday_position > 0:
close_order(context, InstrumentID, exchangeid, direction, yestoday_position, "1")
# 记录日志
log_msg = f"{InstrumentID}触发{'止盈' if profit_condition else '止损'} "
if profit_condition:
log_msg += f"最高盈亏比例:{context.highest_profit_ratio:.2f} 当前盈亏比例:{profit_ratio:.2f} 回撤盈亏比例:{current_drawdown:.2f}%"
else:
log_msg += f"当前价格:{last_price:.2f} 开仓价格:{open_price:.2f} 盈亏亏损比例:{loss_ratio:.2f}"
put_log(log_msg, level="USER_LOG")
else:
put_log("持仓获取失败", level="USER_LOG")
def on_stop(context):
print("移动止盈止损(盈亏比例)风控模块")
模型对比总览
| 模型 | 触发基准 | 参数 | 极值跟踪方式 | 适用场景 |
|---|---|---|---|---|
| 移动_点数 | 盈亏点数 | tp_start_points / tp_points / sl_points |
单一变量 highest_price / lowest_price |
趋势跟踪 + 锁浮盈(单持仓) |
| 移动_价格比例 | 价格比例 | tp_start_rate / tp_rate / sl_rate |
字典 trailing_highs 按合约_方向 |
多持仓独立跟踪 |
| 移动_盈亏比例 | 保证金比例 | tp_start_rate / tp_rate / sl_rate |
单一变量 highest_profit_ratio |
按保证金杠杆跟踪趋势(单持仓) |
关键要点
- 挂载即用:所有模型只处理
BASE_SETTING["Instrument"]挂载合约的持仓,可直接作为风控模块附加到任意策略上,不影响原策略的开仓逻辑 - tick 降频:
on_tick中用counter >= 4每 4 个 tick 才执行一次auto_tpsl,降低风控判断频率,平衡实时性与性能 - 处理防重入:
context.processing标志防止auto_tpsl在一次执行未完成时被重复触发 - 平今平昨:上期所(SHFE)/ 能源中心(INE)必须区分平今(
"3")/ 平昨("1"),其他交易所合并处理;通过TodayPosition/YdPosition/ 冻结量计算可平手数 - 移动止盈三要素:① 激活条件(盈利达启动阈值)→ ② 极值跟踪(最高价/最低价/最高盈亏比)→ ③ 回撤触发(从极值回撤达阈值)
- 多持仓支持:移动_价格比例用
trailing_highs字典按合约_方向键独立跟踪每个持仓;移动_点数和移动_盈亏比例用单一变量(highest_price/highest_profit_ratio),适合单持仓场景 - 状态重置:触发平仓后将极值/激活标志重置为初始值,确保下次开仓后重新跟踪
- 盈亏比例需保证金:移动_盈亏比例需调用
get_symbolinfo获取margin_ratio,以保证金为基准计算盈亏比例
相关阅读
- [核心API 实时行情数据]
- [核心API 账户持仓查询]
- [核心API 合约信息查询]
- [案例:网格策略]
- [风控模型 - 固定止盈止损]

评论
登录后参与讨论,与站内账号体系共用。