GitHub で見る
仮想通貨戦略
概要
Cryptos Strategy は、元の MetaTrader4 エキスパート アドバイザー cryptos.mq4 の高レベルの StockSharp 移植です。 ETH/USD ペアに焦点を当て、Bollinger バンドと線形加重移動平均 (LWMA) を組み合わせてボラティリティ圧縮からのブレイクアウトを捉えます。この戦略は、設定可能なローソク足の高値と安値のスイングを追跡し、検出された範囲の倍数としてテイクプロフィットターゲットを動的に計算します。
取引ロジック
- トレンド検出 – 終値が上部 Bollinger バンドに触れると戦略はショート バイアスに切り替わり、下部バンドに触れるとロング バイアスに切り替わります。また、バンドタッチでは、高値/安値の自動更新が無効になり、現在のスイング値が凍結されます。
- エントリー条件 –
- 終値が LWMA を下回り、バイアスがショートし、アクティブなショート ポジションがない場合にショート ポジションをオープンします。
- 終値が LWMA を上回り、バイアスが長く、アクティブなロングポジションがない場合にロングポジションをオープンします。
- 距離予測 – スイングの高値と安値 (自動または手動で固定) が LWMA からの距離を定義します。ティックで表されるこの距離にテイクプロフィット比率を掛けて、利益目標とリスクベースのポジションサイズを計算します。
- リスク管理 – この戦略は取引ごとのテイクプロフィットとストップロスのレベルを設定します。ロングの場合、ストップはスイングの下に低く配置されます。ショートの場合、スイングハイより上。ストップとターゲットはエントリごとに再計算され、戦略ループ内で適用されます。
- トレーリング イグジット – ロング ポジションが下側の Bollinger バンド (または上側バンドの上のショート) を下回ってクローズした場合、オープン ポジションはすぐにフラットになり、元の EA のトレーリング動作を模倣します。
パラメーター
| パラメータ |
説明 |
CandleType |
すべてのインジケーターの計算に使用されるローソク足シリーズのデータ型。 |
BollingerPeriod, BollingerWidth |
Bollinger バンドの長さと標準偏差の乗数。 |
MaPeriod |
中央価格に基づく線形加重移動平均の期間。 |
LookbackCandles |
自動スイングの高値/安値を決定するために検査されるローソク足の数。 |
TakeProfitRatio |
ETH/USDを取引する際の利益目標に使用される範囲乗数。 |
AlternativeTakeProfitRatio |
他のすべてのシンボルに適用される範囲乗数。 |
RiskPerTrade |
出来高計算ツールが各取引でリスクを負おうとする資本の量 (相場通貨)。 |
ValueIndex, CryptoValueIndex |
非暗号通貨シンボルと暗号通貨シンボルそれぞれのリスクをボリュームに変換する乗数。 |
MinVolume, MaxVolume |
ボリュームステップを交換するための位置合わせ後のポジションサイズのハードバウンド。 |
MinRangeTicks |
ゼロ距離停止を回避するための最小許容投影範囲 (ティック単位)。 |
SpreadPoints |
ティック単位のスプレッドを手動でオーバーライドします (可能な場合は最高の買い値/売り値から自動検出されます)。 |
GlobalTrend |
手動バイアス オーバーライド: 1 は短いセットアップを強制し、2 は長いセットアップを強制し、0 は戦略によって決定されます。 |
AutoHighLow |
有効にすると、スイング ポイントがすべてのローソク足で再計算されます。無効にすると、次のバンドがタッチされるまでフリーズされます。 |
ManualBuyTrigger, ManualSellTrigger |
即時のロングまたはショート エントリを要求するには、true に設定します (実行後にリセット)。 |
SkipBuys, SkipSells |
新しいロングポジションまたはショートポジションのオープンを無効にします。 |
ポジションサイズ
この戦略は MT4 ロジック volume = RiskPerTrade / rangeTicks * valueIndex を複製します。結果は VolumeStep に揃えられ、MinVolume/MaxVolume と商品取引所が課す制限値の間でクリップされます。
使用上の注意
- この戦略は開始時にポートフォリオの価値をチェックします。残高が
RiskPerTrade * 3 未満の場合、取引は無効になり、EA の安全性チェックと一致する警告が記録されます。
- 手動トリガーとバイアス制御により、ライブ取引中の裁量的決定と同期することが可能になります。
- ETH/USD は自動的に
CryptoValueIndex と TakeProfitRatio を使用します。他の機器は代替パラメータに戻ります。
- ストップとターゲットは戦略ループ内で強制されるため、追加の保護モジュールは必要ありません。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Cryptos" MetaTrader expert.
/// Uses Bollinger Bands with a WMA trend filter. Buys when price is below WMA
/// and touches lower band; sells when price is above WMA and touches upper band.
/// </summary>
public class CryptosStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _wmaPeriod;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private ExponentialMovingAverage _bandEma;
private ExponentialMovingAverage _trendEma;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int WmaPeriod
{
get => _wmaPeriod.Value;
set => _wmaPeriod.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerWidth
{
get => _bollingerWidth.Value;
set => _bollingerWidth.Value = value;
}
public CryptosStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signals", "General");
_wmaPeriod = Param(nameof(WmaPeriod), 55)
.SetGreaterThanZero()
.SetDisplay("WMA Period", "Weighted moving average period", "Indicators");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Width", "Bollinger Bands deviation", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bandEma = new ExponentialMovingAverage { Length = BollingerPeriod };
_trendEma = new ExponentialMovingAverage { Length = WmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_bandEma, _trendEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bandEma);
DrawIndicator(area, _trendEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal bandValue, decimal trendValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bandEma.IsFormed || !_trendEma.IsFormed)
return;
var close = candle.ClosePrice;
var bandOffset = bandValue * (BollingerWidth / 100m);
var upperBand = bandValue + bandOffset;
var lowerBand = bandValue - bandOffset;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Buy: price below WMA, touches lower band
if (close < trendValue && close <= lowerBand)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
// Sell: price above WMA, touches upper band
else if (close > trendValue && close >= upperBand)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
// Exit at WMA cross
if (Position > 0 && close >= upperBand)
SellMarket(Position);
else if (Position < 0 && close <= lowerBand)
BuyMarket(Math.Abs(Position));
}
/// <inheritdoc />
protected override void OnReseted()
{
_bandEma = null;
_trendEma = null;
base.OnReseted();
}
}
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 cryptos_strategy(Strategy):
def __init__(self):
super(cryptos_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._wma_period = self.Param("WmaPeriod", 55)
self._bollinger_period = self.Param("BollingerPeriod", 20)
self._bollinger_width = self.Param("BollingerWidth", 2.0)
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def WmaPeriod(self):
return self._wma_period.Value
@WmaPeriod.setter
def WmaPeriod(self, value):
self._wma_period.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
@BollingerWidth.setter
def BollingerWidth(self, value):
self._bollinger_width.Value = value
def OnReseted(self):
super(cryptos_strategy, self).OnReseted()
def OnStarted2(self, time):
super(cryptos_strategy, self).OnStarted2(time)
band_ema = ExponentialMovingAverage()
band_ema.Length = self.BollingerPeriod
trend_ema = ExponentialMovingAverage()
trend_ema.Length = self.WmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(band_ema, trend_ema, self._process_candle).Start()
def _process_candle(self, candle, band_value, trend_value):
if candle.State != CandleStates.Finished:
return
band_val = float(band_value)
trend_val = float(trend_value)
close = float(candle.ClosePrice)
band_offset = band_val * (float(self.BollingerWidth) / 100.0)
upper_band = band_val + band_offset
lower_band = band_val - band_offset
# Buy: price below WMA, touches lower band
if close < trend_val and close <= lower_band:
if self.Position <= 0:
self.BuyMarket()
# Sell: price above WMA, touches upper band
elif close > trend_val and close >= upper_band:
if self.Position >= 0:
self.SellMarket()
# Exit at opposite band
if self.Position > 0 and close >= upper_band:
self.SellMarket()
elif self.Position < 0 and close <= lower_band:
self.BuyMarket()
def CreateClone(self):
return cryptos_strategy()