GitHub で見る
ピップオーバー 8167 戦略
概要
Pipsover 8167 戦略は、ビルド 8167 で配布された MetaTrader 4 エキスパート アドバイザー Pipsover.mq4 の StockSharp ポートです。エキスパートは、前のローソク足の 20 期間単純移動平均への引き戻しの直後に現れる強いチャイキン オシレーター スパイクを検索します。この組み合わせが発生すると、スクリプトはインパルスの方向にポジションをオープンし、固定のストップロスとテイクプロフィットの距離 (元の MQL コードではそれぞれ 70 ポイントと 140 ポイント) でポジションを保護します。この C# バージョンは、高レベルの StockSharp コンポーネントを使用してまったく同じロジックを再構築するため、直接バッファーにアクセスする必要はありません。
この実装では、累積/分配線 (ADL) インジケーターと 2 つの指数移動平均を使用して、MetaTrader の iCustom("Chaikin", ...) によって生成されたチャイキン オシレーター値を再構築します。すべての取引決定はローソク足が完全に閉じるまで延期され、ソース スクリプトから OrdersTotal() および Close[1] / Open[1] チェックが複製されます。
インジケーターとシグナル
- 単純移動平均 (SMA 20) – ローソク足の終値に適用されます。前のローソク足は、実体をセットアップの方向に保ちながら、SMA (ロングの場合は下方に、ショートの場合は上方) を貫通する必要があります。
- チャイキン オシレーター (ADL の EMA 3 – EMA 10) –
iCustom("Chaikin", 0, 0, 1) の読み取り値をミラーリングするために ADL ストリームから内部的に再構築されます。エントリーおよびエグジットのスレッショルドは絶対オシレーター単位で表されます。
- プライス アクション フィルター – この戦略は、前のローソク足の実体の方向をチェックします。強気の実体はロング取引を可能にし、弱気の実体はショートを可能にします。
取引ルール
ロングエントリー
- 前のローソク足は強気で終了しました (
Close[1] > Open[1])。
- 以前の安値は、そのローソク足の SMA20 値を下回ります。
- 以前の Chaikin 値は
-OpenLevel (デフォルトは 55) 未満です。
- 現在募集中のポジションはありません。
ショートエントリー
- 前のローソク足は弱気で終了しました (
Close[1] < Open[1])。
- 以前の高値は、そのローソク足の SMA20 値を上回っています。
- 以前のチャイキン値は
OpenLevel を超えています。
- 現在募集中のポジションはありません。
終了条件
- ロング ポジションは、次のローソク足が満たされると終了します: 弱気の実体、SMA20 を超える高値、およびチャイキンが
CloseLevel (デフォルト 90) を超える。
- ショート ポジションは、次のローソク足が強気の実体、SMA20 を下回る安値、およびチャイキンが
-CloseLevel を下回るときに閉じます。
- さらに、すべての取引には
StopLossPoints の保護ストップと TakeProfitPoints のテイクプロフィットがあり、どちらも選択した商品の価格ステップで表されます。
リスク管理
- ストップロス距離:
StopLossPoints × PriceStep (デフォルトは 70 ポイント)。
- 利食い距離:
TakeProfitPoints × PriceStep (デフォルトは 140 ポイント)。
- ポジション サイズ:
TradeVolume 経由で設定可能。StockSharp 戦略の Volume プロパティに直接マッピングされ、すべての成行注文に使用されます。
パラメーター
| パラメータ |
デフォルト |
説明 |
TradeVolume |
0.1 |
成行注文の量 (証券に応じてロットまたは契約)。 |
MaLength |
20 |
プルバックチェックに使用される SMA の期間。 |
StopLossPoints |
70 |
価格ステップで測定されるストップロス距離。 |
TakeProfitPoints |
140 |
価格ステップで測定される利食い距離。 |
OpenLevel |
55 |
新しいエントリのロックを解除する絶対チャイキン オシレーターのしきい値。 |
CloseLevel |
90 |
強制的に終了するチャイキン オシレーターの絶対しきい値。 |
ChaikinFastLength |
3 |
Chaikin 再構築における高速な EMA の長さ。 |
ChaikinSlowLength |
10 |
Chaikin 再構成では EMA の長さが遅いです。 |
CandleType |
H1 |
ローソク足のサブスクライブとインジケーターの計算に使用される時間枠。 |
実装メモ
- ローソク足とインジケーターは
SubscribeCandles().Bind(...) を介して接続されているため、戦略は高レベルの API ガイドラインの範囲内に留まります。
- Chaikin 値は、ADL 読み取り値を 2 つの EMA オブジェクトにフィードすることでメモリ内で計算され、インジケーター バッファーでの
GetValue() などの禁止された呼び出しを回避します。
- 以前のローソク足の情報は、MQL アクセス パターン
Close[1]、Low[1]、High[1]、および iCustom(...,1) を再現するために、ストラテジー ステート内にキャッシュされます。
- 元のエキスパートがサーバー側の保護注文ではなく、静的オフセットを使用して単純な成行注文を送信したため、ストップロスとテイクプロフィットのレベルは手動で追跡されます。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Pipsover8167Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;
private int _cooldown;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Pipsover8167Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevEma = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close; _prevEma = ema;
return;
}
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 6;
}
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 6;
}
_prevClose = close; _prevEma = ema;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage
class pipsover8167_strategy(Strategy):
def __init__(self):
super(pipsover8167_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown = 0
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(pipsover8167_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
self._prev_ema = ema_val
return
if self._prev_close <= self._prev_ema and close > ema_val and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 6
elif self._prev_close >= self._prev_ema and close < ema_val and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 6
self._prev_close = close
self._prev_ema = ema_val
def OnReseted(self):
super(pipsover8167_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown = 0
def CreateClone(self):
return pipsover8167_strategy()