Panel Joke 策略
该策略是将 MetaTrader 的 panel-joke 系统转换为 StockSharp。它比较当前和上一根 K 线的七个价格指标(开盘价、高点、低点、high/low 平均值、收盘价、high/low/close 平均值以及 high/low/close 加权平均值)。每个上涨的指标会增加买入计数器,每个下降的指标会增加卖出计数器。
当 Enable Autopilot 参数为 true 时,策略会根据计数器的高低自动开仓或反向开仓,不使用额外的指标或止损规则。
详情
- 入场条件:
- 做多:Buy counter > Sell counter。
- 做空:Sell counter > Buy counter。
- 出场条件:出现相反信号时反向。
- 止损:无。
- 默认值:
Enable Autopilot=true。Candle Type= 5 分钟。
- 筛选:
- 类别:Price action
- 方向:双向
- 指标:无
- 止损:否
- 复杂度:基础
- 时间框架:日内
- 季节性:否
- 神经网络:否
- 背离:否
- 风险级别:高
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simple heuristic strategy comparing current and previous candles.
/// Counts how many price components moved up or down and trades on majority.
/// </summary>
public class PanelJokeStrategy : Strategy
{
private readonly StrategyParam<bool> _enableAutopilot;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevOpen;
private decimal _prevHigh;
private decimal _prevLow;
private decimal _prevClose;
private bool _hasPrev;
/// <summary>
/// Enables automatic order execution.
/// </summary>
public bool EnableAutopilot
{
get => _enableAutopilot.Value;
set => _enableAutopilot.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes parameters.
/// </summary>
public PanelJokeStrategy()
{
_enableAutopilot = Param(nameof(EnableAutopilot), true)
.SetDisplay("Enable Autopilot", "Automatically trade based on signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for incoming candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOpen = 0;
_prevHigh = 0;
_prevLow = 0;
_prevClose = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var warmup = new ExponentialMovingAverage { Length = 5 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(warmup, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal _warmupVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevOpen = candle.OpenPrice;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevClose = candle.ClosePrice;
_hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevOpen = candle.OpenPrice;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevClose = candle.ClosePrice;
return;
}
var buy = 0;
var sell = 0;
// Compare each OHLC component
if (candle.OpenPrice > _prevOpen)
buy++;
else
sell++;
if (candle.HighPrice > _prevHigh)
buy++;
else
sell++;
if (candle.LowPrice > _prevLow)
buy++;
else
sell++;
var avgHL = (candle.HighPrice + candle.LowPrice) / 2m;
var prevAvgHL = (_prevHigh + _prevLow) / 2m;
if (avgHL > prevAvgHL)
buy++;
else
sell++;
if (candle.ClosePrice > _prevClose)
buy++;
else
sell++;
var avgHLC = (candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 3m;
var prevAvgHLC = (_prevHigh + _prevLow + _prevClose) / 3m;
if (avgHLC > prevAvgHLC)
buy++;
else
sell++;
var avgHLCC = (candle.HighPrice + candle.LowPrice + 2m * candle.ClosePrice) / 4m;
var prevAvgHLCC = (_prevHigh + _prevLow + 2m * _prevClose) / 4m;
if (avgHLCC > prevAvgHLCC)
buy++;
else
sell++;
if (buy > sell && Position <= 0)
BuyMarket();
else if (sell > buy && Position >= 0)
SellMarket();
_prevOpen = candle.OpenPrice;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevClose = candle.ClosePrice;
}
}
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 panel_joke_strategy(Strategy):
def __init__(self):
super(panel_joke_strategy, self).__init__()
self._enable_autopilot = self.Param("EnableAutopilot", True) \
.SetDisplay("Enable Autopilot", "Automatically trade based on signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for incoming candles", "General")
self._prev_open = 0.0
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def enable_autopilot(self):
return self._enable_autopilot.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(panel_joke_strategy, self).OnReseted()
self._prev_open = 0.0
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(panel_joke_strategy, self).OnStarted2(time)
warmup = ExponentialMovingAverage()
warmup.Length = 5
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(warmup, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, _warmup_val):
if candle.State != CandleStates.Finished:
return
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
if not self._has_prev:
self._prev_open = o
self._prev_high = h
self._prev_low = l
self._prev_close = c
self._has_prev = True
return
buy = 0
sell = 0
if o > self._prev_open:
buy += 1
else:
sell += 1
if h > self._prev_high:
buy += 1
else:
sell += 1
if l > self._prev_low:
buy += 1
else:
sell += 1
avg_hl = (h + l) / 2.0
prev_avg_hl = (self._prev_high + self._prev_low) / 2.0
if avg_hl > prev_avg_hl:
buy += 1
else:
sell += 1
if c > self._prev_close:
buy += 1
else:
sell += 1
avg_hlc = (h + l + c) / 3.0
prev_avg_hlc = (self._prev_high + self._prev_low + self._prev_close) / 3.0
if avg_hlc > prev_avg_hlc:
buy += 1
else:
sell += 1
avg_hlcc = (h + l + 2.0 * c) / 4.0
prev_avg_hlcc = (self._prev_high + self._prev_low + 2.0 * self._prev_close) / 4.0
if avg_hlcc > prev_avg_hlcc:
buy += 1
else:
sell += 1
if buy > sell and self.Position <= 0:
self.BuyMarket()
elif sell > buy and self.Position >= 0:
self.SellMarket()
self._prev_open = o
self._prev_high = h
self._prev_low = l
self._prev_close = c
def CreateClone(self):
return panel_joke_strategy()