首页
/
策略示例
在 GitHub 上查看
Mission Impossible Power Two Open 策略
概述
本策略是 MetaTrader 智能交易程序 “Mission Impossible Power Two Open” 在 StockSharp 平台上的移植版本。策略追踪最近收盘完成的蜡烛方向,并在同一方向开启交易篮子。当价格朝不利方向移动时,会按照固定的点差网格继续加仓。每次加仓的手数会根据浮动亏损与 Power 系数成比例地放大,与原版 EA 的逻辑保持一致。所有仓位共用同一组止盈与止损,且在每次成交后都会重新计算。
交易流程
信号识别 :在每根蜡烛收盘时比较上一根蜡烛的开盘价与收盘价。
若收盘价高于开盘价,则生成做多信号。
若收盘价低于开盘价,则生成做空信号。
若收盘价等于开盘价,则不启动新的篮子。
首笔下单 :若对应方向尚无活动网格,则以 BaseVolume 手数发送市价单。
网格加仓 :当篮子存在时,持续评估最新成交价与当前收盘价之间的距离。
多头在价格下跌至少 GridStepPips * PriceStep 后才允许再次买入。
空头在价格上涨同样的距离后才允许再次卖出。
每个方向的加仓次数最多为 MaxTrades 次。
手数放大 :每次准备加仓时,先计算篮子的浮动亏损,将其乘以 Power * 0.0001 并加到 BaseVolume 上。最终手数会根据交易品种的 VolumeStep 进行对齐,并受 MinVolume、MaxVolume 以及参数 MaxVolume 限制。
止盈止损 :每次成交后重新计算整篮仓位的目标价格。
只有一笔仓位时,止盈距离为 TakeProfitFirstPips,止损距离为 StopLossPips。
两笔及以上仓位时,两者都基于成交量加权平均价计算,止盈距离改为 TakeProfitNextPips。
一旦价格触及任一目标,立即通过反向市价单平掉该方向的全部仓位。
多空独立 :多头和空头篮子各自管理,可在信号频繁反转时同时持有对冲仓位。
参数
参数
类型
默认值
说明
BaseVolume
decimal
0.01
新篮子的初始手数。
MaxVolume
decimal
2
单笔市价单允许的最大手数。
Power
decimal
13
根据浮动亏损放大手数时使用的系数。
StopLossPips
int
400
共享止损距离,对应价格步长数量。
TakeProfitFirstPips
int
15
仅有首笔仓位时的止盈距离。
TakeProfitNextPips
int
7
网格包含两笔及以上仓位时的止盈距离。
GridStepPips
int
21
触发下一次加仓所需的最小不利移动(以价格步长表示)。
MaxTrades
int
16
单个方向允许的最大网格次数。
CandleType
DataType
TimeSpan.FromMinutes(5).TimeFrame()
用于生成信号和控制网格的蜡烛类型。
说明
手数始终与交易所提供的 VolumeStep 对齐,并遵守 MinVolume 与 MaxVolume 限制。
多头与空头状态完全独立,实现了原始 EA 中针对不同魔术号分别管理仓位的行为。
每次加仓后都会重新计算止盈/止损,并将价格四舍五入到最近的 PriceStep,这与原策略频繁修改订单的方式一致。
策略无需任何技术指标,完全依赖蜡烛数据和组合状态进行决策,与 MQL4 版本保持一致。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Mission Impossible Power Two Open strategy: Candle direction with EMA trend filter.
/// Buys on bullish candle when above EMA, sells on bearish candle when below EMA.
/// </summary>
public class MissionImpossiblePowerTwoOpenStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private bool _wasBullishSignal;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public MissionImpossiblePowerTwoOpenStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullishSignal = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_wasBullishSignal = false;
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var open = candle.OpenPrice;
var bullish = close > open;
var bearish = close < open;
var bullishSignal = bullish && close > emaValue;
var bearishSignal = bearish && close < emaValue;
var crossedUp = bullishSignal && (!_hasPrevSignal || !_wasBullishSignal);
var crossedDown = bearishSignal && (!_hasPrevSignal || _wasBullishSignal);
if (crossedUp && Position <= 0)
BuyMarket();
else if (crossedDown && Position >= 0)
SellMarket();
if (bullishSignal || bearishSignal)
{
_wasBullishSignal = bullishSignal;
_hasPrevSignal = 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 mission_impossible_power_two_open_strategy(Strategy):
def __init__(self):
super(mission_impossible_power_two_open_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ema_period = self.Param("EmaPeriod", 50)
self._was_bullish_signal = False
self._has_prev_signal = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(mission_impossible_power_two_open_strategy, self).OnReseted()
self._was_bullish_signal = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(mission_impossible_power_two_open_strategy, self).OnStarted2(time)
self._was_bullish_signal = False
self._has_prev_signal = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ema_val = float(ema_value)
bullish = close > open_price
bearish = close < open_price
bullish_signal = bullish and close > ema_val
bearish_signal = bearish and close < ema_val
crossed_up = bullish_signal and (not self._has_prev_signal or not self._was_bullish_signal)
crossed_down = bearish_signal and (not self._has_prev_signal or self._was_bullish_signal)
if crossed_up and self.Position <= 0:
self.BuyMarket()
elif crossed_down and self.Position >= 0:
self.SellMarket()
if bullish_signal or bearish_signal:
self._was_bullish_signal = bullish_signal
self._has_prev_signal = True
def CreateClone(self):
return mission_impossible_power_two_open_strategy()