GitHub で見る
CCFp通貨強弱戦略
概要
この戦略はクラシックなMetaTrader CCFpエキスパートアドバイザーをStockSharpの高レベルAPIにポートします。7つのUSDベースの主要通貨ペア(EURUSD、GBPUSD、AUDUSD、NZDUSD、USDCAD、USDCHF、USDJPY)の速い・遅い単純移動平均の比率を使用して、8つの主要通貨(USD、EUR、GBP、CHF、JPY、AUD、CAD、NZD)の相対的な強さスコアを計算します。2つの通貨強度の差が設定可能なしきい値を上回ると、戦略は弱い通貨に対して強い通貨を表現する成行ポジションを開設します。
実装は推奨された高レベルアーキテクチャに従っています:各インストゥルメントには独自のローソク足サブスクリプションがあり、インジケーターはBindを通じてバインドされ、注文管理は成行注文でRegisterOrderを使用します。実行された注文のコメントは元の(TOPDOWN)フォーマットを再利用して、MQLバージョンと同じ簿記スタイルを維持します。
必要なインストゥルメント
戦略パラメーターに以下の証券を添付します:
EURUSD
GBPUSD
AUDUSD
NZDUSD
USDCAD
USDCHF
USDJPY
7つのペアはすべてCandle Typeパラメーターを通じて設定された同じ時間軸を共有する必要があります。
パラメーター
| パラメーター |
説明 |
Fast MA |
強度計算に使用される速い移動平均期間。 |
Slow MA |
強度計算に使用される遅い移動平均期間。 |
Strength Step |
新しいシグナルをトリガーするために超えなければならない2つの通貨間の最小差。 |
Close Opposite |
有効にすると、戦略は新しい注文を送る前に反対のポジションをクローズします。 |
Candle Type |
インジケーターによって処理されるローソク足シリーズ。 |
基本Volume |
標準のStrategy.Volumeプロパティから取得され、送信された各成行注文に使用されます。 |
取引ロジック
- 7つのUSD主要ペアのそれぞれは独自の単純移動平均ペア(速い・遅い)でサブスクライブされます。
- 完了したローソク足が届くたびに、戦略は遅い・速い平均の比率をオリジナルのCCFpインジケーターによって生成されるのと同じ合成強度値に変換します。
- 7つのペアすべてが更新された後、8つの通貨強度スコアが再計算されます。
- 「top」通貨と「down」通貨の差が
Strength Stepレベルを上方に超え、top通貨が上昇しdown通貨が下落している場合、機会が検出されます。
- 戦略は強い通貨へのロングエクスポージャーと弱い通貨へのショートエクスポージャーを表現する成行注文を開設します:
- USDが強い通貨の場合、相手ペアに1つの注文のみが置かれます(例:short
EURUSD)。
- USDが弱い通貨の場合、戦略は強い通貨が基軸通貨であるペアを買います(例:long
EURUSD)。
- 両方の通貨が非USDの場合、戦略は2つの注文を送ります:top通貨のUSDに対するロングとdown通貨のUSDに対するショート。
Close Oppositeが有効で、ターゲットペアにまだ反対のポジションが開いている場合、戦略は新しいトレードに入る前にまず成行クローズ注文を送ります。
リスク管理
- 戦略は明示的なストップロスまたはテイクプロフィット注文を添付しません;リスク管理は
Close Oppositeフラグと手動ポートフォリオ管理ツールによって処理されます。
- エントリーサイズは
Volumeプロパティによって制御されます。口座サイズと各セグメントの希望するエクスポージャーに応じて設定します。
オリジナルMQL実装との違い
- 通貨強度計算は単一の時間軸でStockSharpの
SimpleMovingAverageインジケーターを使用します。MQLインジケーターからのマルチタイムフレーム係数スタッキングは、Fast MAとSlow MA期間を調整することでエミュレートできます。
- 保護ストップは自動的にトレーリングされません;代わりに、戦略はエントリー/エグジットロジックの再現に集中し、高度なリスク管理をStockSharpのポートフォリオ層に任せます。
- 注文ルーティングはMetaTraderトレードオブジェクトの代わりに高レベルの
RegisterOrderヘルパーとStockSharpのセキュリティ参照を使用します。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// CCFp Currency Strength strategy (simplified). Uses fast/slow EMA crossover
/// to detect momentum shifts, inspired by currency strength comparison.
/// </summary>
public class CcfpCurrencyStrengthStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public CcfpCurrencyStrengthStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_fastLength = Param(nameof(FastLength), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast EMA period", "Indicators");
_slowLength = Param(nameof(SlowLength), 20)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = FastLength };
var emaSlow = new ExponentialMovingAverage { Length = SlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastVal;
prevSlow = slowVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastVal;
prevSlow = slowVal;
return;
}
// Fast EMA crosses above slow - bullish
if (prevFast <= prevSlow && fastVal > slowVal && Position <= 0)
BuyMarket();
// Fast EMA crosses below slow - bearish
else if (prevFast >= prevSlow && fastVal < slowVal && Position >= 0)
SellMarket();
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
}
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 ccfp_currency_strength_strategy(Strategy):
def __init__(self):
super(ccfp_currency_strength_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._fast_length = self.Param("FastLength", 5) \
.SetDisplay("Fast Length", "Fast EMA period", "Indicators")
self._slow_length = self.Param("SlowLength", 20) \
.SetDisplay("Slow Length", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
def OnReseted(self):
super(ccfp_currency_strength_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ccfp_currency_strength_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastLength
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return ccfp_currency_strength_strategy()