GitHub で見る
莫大な収入を得る戦略
概要
この戦略は、MetaTrader 4 エキスパート アドバイザー「Huge Income」の StockSharp 移植です。オリジナルのロボットは、日足の始値から離れてブレイクアウトの方向に単一のポジションに入る日中の動きを探します。 StockSharp バージョンは、日中のローソク足から毎日の高値/安値の範囲を再構築することで同じ考え方を維持し、一度に 1 つのポジションのみをオープンし、設定された市場が閉じる直前に強制的に決済します。
データと環境
- 商品: 信頼できる価格ステップを提供する任意のシンボル (
PriceStep)。このロジックは外国為替ペア用に設計されていますが、pip パラメーターを調整した後は他の金融商品でも機能します。
- タイムフレーム: デフォルトでは、この戦略は 15 分足のローソク足をサブスクライブして、毎日の始値、高値、安値を再構築します。データ ソースの解像度が優れている場合は、別のローソク足タイプに切り替えることができます。
- セッション: チャート時間は、MetaTrader スクリプトとまったく同様にブローカー/サーバーのクロックに従うことが期待されます。そのタイムゾーンに従って締め切り時間を設定します。
取引ロジック
- 新しいローソクが到着するたびに、当日の統計を再構築します。その日の最初のローソク足が始値を提供し、ランニング高値/安値を初期化します。
- いつでも 1 つのポジション (ロングまたはショート) のみが許可されます。未決注文は使用されません。この戦略は成行注文に依存しています。
- 長いセットアップ:
- 現在の終値は日次始値を上回っています。
- 始値と当日の安値の間の距離が
MinimumRangePips を超えています (PriceStep を介して価格単位に変換)。
- 現在の時間は厳密に
BuyCutoffHour より小さいです。
- 簡単なセットアップ:
- 現在の終値は日次始値を下回っています。
- 今日の高値と始値の間の距離は
MinimumRangePips を超えています。
- 現在の時間は厳密に
SellCutoffHour より小さいです。
- いずれかの設定が満たされると、戦略はサイズ
TradeVolume の成行注文を送信し、ポジションが再びフラットになるまで新しいエントリーの評価を停止します。
MarketCloseHour に達すると、オープンポジションは成行注文でクローズされます。これは、週末の終値近くに取引を清算する MetaTrader ロジックを反映しています。
リスクと資金の管理
TradeVolume は固定注文サイズです。元のスクリプトには平均化やマーチンゲール動作がないため、StockSharp ポートは一定のボリュームを維持します。
- 明示的なストップロスやテイクプロフィットのレベルはありません。エキスパートアドバイザーは、日次範囲フィルターとセッション終了近くの強制終了を利用してリスクを制御します。必要に応じてストップやトレーリング ロジックを追加することで戦略を拡張できます。
パラメーター
| パラメータ |
説明 |
TradeVolume |
BuyMarket または SellMarket の注文を送信するときに使用されるポジション サイズ。 |
MinimumRangePips |
取引が許可されるまでの毎日の始値と反対の極端な値の間の最小距離 (ピップ単位)。 Security.PriceStep を使用して絶対価格差に変換されます。 |
BuyCutoffHour |
新しい長いエントリを開くことができる最後の 1 時間 (0 ~ 23)。比較は厳密です (currentHour < BuyCutoffHour)。 |
SellCutoffHour |
新しい短いエントリがオープンされる可能性がある最後の 1 時間 (0 ~ 23)。 |
MarketCloseHour |
すべてのオープンポジションが清算される時刻。元の金曜日の EA の閉店動作と一致させるには、これを 23 に設定します。 |
CandleType |
ローソク足を購読し、毎日の統計を再構築するために使用される時間枠。 |
MT4版との違い
- StockSharp は、個々のティックではなくローソク足データを受け取ります。ブローカーの MetaTrader フィードがティックごとの更新に依存している場合は、同じ応答性をエミュレートするのに十分短いローソク足間隔を選択してください。
- 機器に
PriceStep がない場合、MinimumRangePips フィルタは自動的に無効になります。その場合、始値の上/下でのすべてのブレイクアウトが受け入れられます。
- すべての取引は成行注文で実行され、
MarketCloseHour ですぐにフラット化され、未決注文なしで元のコードの OrderClose ループが複製されます。
使い方のヒント
- 好みの実行速度に合わせてローソク足の時間枠を調整します。ローソク足が短いほど、毎日の高値/安値をより正確に追跡できますが、より多くのデータが必要になります。
- 商品の取引時間を確認してください。設定した
MarketCloseHour よりも早く市場が終了した場合、強制終了は次の営業日にトリガーされます。
- 元の設計を超えるストップロスまたはドローダウン制限が必要な場合は、戦略をポートフォリオまたはアカウントレベルの保護 (例:
StartProtection) と組み合わせます。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Huge Income: EMA trend following with ATR stops.
/// </summary>
public class HugeIncomeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevClose;
private decimal _entryPrice;
public HugeIncomeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0; _entryPrice = 0;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (atrVal <= 0 || _prevClose == 0) { _prevClose = candle.ClosePrice; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if (close < emaVal || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close > emaVal || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (close > emaVal && _prevClose <= emaVal) { _entryPrice = close; BuyMarket(); }
else if (close < emaVal && _prevClose >= emaVal) { _entryPrice = close; SellMarket(); }
}
_prevClose = close;
}
}
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, AverageTrueRange
class huge_income_strategy(Strategy):
def __init__(self):
super(huge_income_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_close = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(huge_income_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._entry_price = 0.0
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
ev = float(ema_val)
av = float(atr_val)
close = float(candle.ClosePrice)
if av <= 0 or self._prev_close == 0:
self._prev_close = close
return
if self.Position > 0:
if close < ev or close <= self._entry_price - av * 2.0:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close > ev or close >= self._entry_price + av * 2.0:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = close
return
if self.Position == 0:
if close > ev and self._prev_close <= ev:
self._entry_price = close
self.BuyMarket()
elif close < ev and self._prev_close >= ev:
self._entry_price = close
self.SellMarket()
self._prev_close = close
def OnReseted(self):
super(huge_income_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
def CreateClone(self):
return huge_income_strategy()