在 GitHub 上查看
Daily Target 策略
概述
DailyTargetStrategy 复刻了 MetaTrader 4 顾问程序 “Daily Target”。策略实时统计当日的浮动盈亏与已实现盈亏之和,
一旦达到设定的盈利目标或者跌破允许的最大亏损,就会立即撤销所有挂单并用市价单平掉仓位,直到次日才允许继续交易。
运行逻辑
- 启动阶段
OnStarted 中调用 ResetDailySnapshot 记录当前日期以及当天开始时的已实现盈亏。
- 通过
SubscribeLevel1() 获取最新的买一/卖一报价,以便精确计算浮动盈亏。
SubscribeTrades() 用来保存最近成交价,在缺少报价时作为备用价格来源。
- 设定 1 分钟定时器,即使市场静止也能及时发现日期切换。
- 盈亏评估
EvaluateDailyThresholds 将当前 PnL 与基准值作差得到当日已实现盈亏,并叠加根据最新报价(或成交价)计算出的浮动盈亏。
- 当总盈亏达到盈利目标或跌至最大亏损阈值以下时,调用
TriggerDailyStop 执行紧急处理。
- 紧急退出
TriggerDailyStop 写入提示日志、取消全部未成交订单,并根据持仓方向发送对冲市价单以平仓。
_dailyStopTriggered 标记可防止当日内再次入场;日期发生变化时,ResetDailySnapshot 会清除此标记并重新记录盈亏基准。
参数
| 名称 |
默认值 |
说明 |
DailyTarget |
10 |
以账户货币计价的日内盈利目标;总盈亏达到该值后,当日停止交易。 |
DailyMaxLoss |
0 |
允许的最大日内亏损(账户货币)。设置为 0 可关闭该限制;当总盈亏低于负阈值时停止交易。 |
其他说明
- 策略仅管理分配给该实例的主交易品种,与原版 MQL 顾问的单品种模式一致。
- 浮动盈亏计算时,多头使用买价 Bid,空头使用卖价 Ask;若缺少报价,则回退到最近成交价。
- 本目录只包含 C# 高阶 API 实现,暂不提供 Python 版本。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Daily Target strategy: TEMA crossover.
/// Buys when fast TEMA crosses above slow TEMA, sells on cross below.
/// </summary>
public class DailyTargetStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DailyTargetStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast TEMA", "Fast TEMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow TEMA", "Slow TEMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class daily_target_strategy(Strategy):
def __init__(self):
super(daily_target_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_period = self.Param("FastPeriod", 10)
self._slow_period = self.Param("SlowPeriod", 30)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
def OnReseted(self):
super(daily_target_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(daily_target_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._has_prev:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
else:
if fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
def CreateClone(self):
return daily_target_strategy()