在 GitHub 上查看
Alexav SpeedUp M1 策略
概述
Alexav SpeedUp M1 策略 是 MetaTrader 4 智能交易系统 "Alexav_SpeedUp_M1" 的直接移植版本。策略针对已经收盘的日内 K 线主体进行评估,只要实体长度超过可配置的阈值便立即市价入场。建仓之后,它会按照 MetaTrader 的习惯为持仓附加止损、止盈以及追踪止损单。
移植完全基于 StockSharp 的高级 API:通过 SubscribeCandles 订阅蜡烛数据,通过 level1 行情获取用于追踪的买一/卖一价格,并使用 BuyStop、SellStop、BuyLimit 和 SellLimit 等便捷方法来挂出保护性订单,无需编写任何自定义指标计算。
信号生成
- 策略检查所选时间框架内每一根已收盘的蜡烛。
- 当蜡烛收盘价高于开盘价,并且差值超过 Body Threshold(实体阈值)时,策略以市价开多或反向开多。
- 当蜡烛收盘价低于开盘价,并且差值超过同一阈值时,策略以市价开空或反向开空。
- 如果存在反向持仓,策略会自动在市价单中追加对应的手数以平掉旧仓,从而忠实还原原始 EA 的行为。
订单管理
- 初始止损:只要仓位增加,即在多单入场价下方(空单入场价上方)按照配置的点数挂出保护性止损单。
- 止盈:根据 Take Profit (points) 参数,在入场方向的目标价位挂出同等手数的限价单。
- 追踪止损:借助 level1 的买一/卖一价格监控浮动盈亏,当未实现利润超过追踪距离时,保护性止损会沿着价格移动,保持设定的间距且绝不回撤。
- 当仓位回到零时,所有保护性订单都会被取消。
移植保持了原策略的简洁性——不会额外引入过滤条件、指标或风险控制,逻辑与 MQL 实现保持一致。
参数
| 名称 |
说明 |
| Lot Size |
每笔市价单的基础手数(以标准手计)。在反向开仓时,系统会自动增加手数以对冲原有仓位。 |
| Take Profit (points) |
入场价到止盈价之间的距离,单位为 MetaTrader 的点(会根据品种的最小跳动单位转换)。 |
| Initial Stop (points) |
入场价到初始止损价之间的距离,单位同上。 |
| Trailing Stop (points) |
当行情朝有利方向运行时,追踪止损保持的固定距离。设为 0 可以关闭追踪功能。 |
| Body Threshold |
蜡烛收盘价与开盘价的最小差值,只有超过该阈值才会触发交易。 |
| Candle Type |
用于生成信号的蜡烛序列(时间框架),默认与原 EA 的一分钟图相同。 |
使用说明
- 请确保交易品种提供有效的
PriceStep。如果缺失,策略会退化为直接把点数视为价格差值。
- 追踪止损需要 level1 行情支持(买一/卖一价)。若只有蜡烛数据,则追踪功能不会启动。
- 策略面向日内交易,通过内部逻辑保证每根蜡烛最多触发一次交易,与原始 MQL 脚本保持一致。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Alexav SpeedUp M1 Body strategy.
/// Trades based on large candle body breakouts.
/// Buys after a large bullish candle, sells after a large bearish candle.
/// Uses ATR to define "large" body threshold.
/// </summary>
public class AlexavSpeedUpM1BodyBreakStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _bodyMultiplier;
private readonly StrategyParam<DataType> _candleType;
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal BodyMultiplier { get => _bodyMultiplier.Value; set => _bodyMultiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AlexavSpeedUpM1BodyBreakStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "ATR period for body threshold", "Indicators");
_bodyMultiplier = Param(nameof(BodyMultiplier), 1.0m)
.SetDisplay("Body Multiplier", "Body must exceed ATR * multiplier", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var body = candle.ClosePrice - candle.OpenPrice;
var absBody = Math.Abs(body);
var threshold = atrValue * BodyMultiplier;
if (absBody < threshold)
return;
// Large bullish candle - buy
if (body > 0 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Large bearish candle - sell
else if (body < 0 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class alexav_speed_up_m1_body_break_strategy(Strategy):
"""Alexav SpeedUp M1 Body strategy.
Trades based on large candle body breakouts.
Buys after a large bullish candle, sells after a large bearish candle.
Uses ATR to define large body threshold."""
def __init__(self):
super(alexav_speed_up_m1_body_break_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for body threshold", "Indicators")
self._body_multiplier = self.Param("BodyMultiplier", 1.0) \
.SetDisplay("Body Multiplier", "Body must exceed ATR * multiplier", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def BodyMultiplier(self):
return self._body_multiplier.Value
def OnReseted(self):
super(alexav_speed_up_m1_body_break_strategy, self).OnReseted()
def OnStarted2(self, time):
super(alexav_speed_up_m1_body_break_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(atr, self._process_candle).Start()
def _process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
body = close - open_price
abs_body = abs(body)
atr_val = float(atr_value)
threshold = atr_val * float(self.BodyMultiplier)
if abs_body < threshold:
return
# Large bullish candle - buy
if body > 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Large bearish candle - sell
elif body < 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return alexav_speed_up_m1_body_break_strategy()