GitHub で見る
NNFX 自動車取引戦略
概要
NNFX 自動取引戦略 は、StockSharp 内の元の NNFX MetaTrader 4 パネルのリスク評価と管理ワークフローを複製します。この戦略では、グラフィカル インターフェイスの代わりに、パラメータを通じて手動コマンドを公開します。トレーダーはロングまたはショートのエントリーをリクエストしたり、エクスポージャーを即座に平坦化したり、エキスパートアドバイザーを反映した損益分岐点ロジックやトレーリングロジックを適用したりできます。
主な特徴:
- ATR 主導のボラティリティ サイジング。手動ストップとテイクプロフィット距離のオプションのオーバーライドを備えています。
- ポジションエントリーは 2 つの部分に分割されます。1 つは予測されたターゲットを含むもの、もう 1 つは裁量管理のために残されたランナーです。
- 損益分岐点コマンドとトレーリング コマンドはオンデマンドで動作し、足ごとに自動的に実行することなく、保存されているストップ レベルを更新します。
- MQL スクリプトの動作に合わせて、金銭的リスクを計算するときに追加の資本を含めることができます。
取引ロジック
- ATR コレクション – ストラテジーは、設定されたローソク足タイプをサブスクライブし、平均トゥルー レンジ インジケーターを処理します。
UsePreviousDailyAtr が有効な場合、元のスクリプトを模倣して、新しい取引日の最初の 12 時間に前日の ATR の値がコピーされます。
- リスクベースのサイジング – 手動の
Buy または Sell コマンドで、エンジンは保護停止距離を使用してユニットあたりの金銭的リスクを計算し、必要なリスクのパーセンテージを実行可能なボリュームに変換します。
- ポジション分割 – エントリーボリュームは 2 つの半分に分割されます。前半部分は、投影されたターゲットに触れると自動的に清算されますが、後半部分はトレーダーがさらにコマンドを発行するまで残ります。
- ストップの処理 – 最初のストップは内部に保存され、完成したキャンドルごとに評価されます。手動コマンドにより、ストップを損益分岐点までプッシュしたり、NNFX トレーリングフォーミュラに従ってストップを進めることができます。
- 出口コントロール –
CloseAll はすぐに帳簿をフラットにしますが、ストップ違反または部分的なターゲットは、計算されたボリュームを尊重して市場からの出口を引き起こします。
パラメーター
| パラメータ |
デフォルト |
説明 |
RiskPercent |
2.0 |
取引ごとにリスクを負うアカウント資本(+ AdditionalCapital)の割合。 |
AdditionalCapital |
0 |
ポジションのサイジング時に資本ベースに追加資本が追加されます。 |
UseAdvancedTargets |
false |
リスク距離を ATR の倍数から手動の pip 値に切り替えます。 |
AdvancedStopPips |
0 |
アドバンスモードがアクティブな場合の停止距離 (pips)。 |
AdvancedTakeProfitPips |
0 |
詳細モードがアクティブな場合の部分的な終了のターゲット距離 (ピップ単位)。 |
UsePreviousDailyAtr |
true |
新しい日の最初の 12 時間に、前の毎日の ATR をコピーします。 |
AtrPeriod |
14 |
ATR ルックバックの長さ。 |
AtrStopMultiplier |
1.5 |
停止距離を計算するときに ATR に適用される乗数。 |
AtrTakeProfitMultiplier |
1.0 |
利食い距離を計算するときに ATR に適用される乗数。 |
CandleType |
1 Minute |
ATR と価格監視に使用されるローソクの種類。 |
BuyCommand |
false |
手動フラグ – 長いエントリを要求するには、true に設定します。自動的にリセットされます。 |
SellCommand |
false |
手動フラグ – 短いエントリを要求するには、true に設定します。自動的にリセットされます。 |
BreakevenCommand |
false |
手動フラグ – 保護ストップをエントリー価格に移動します。自動的にリセットされます。 |
TrailingCommand |
false |
手動フラグ – NNFX トレーリング式を 1 回適用します。自動的にリセットされます。 |
CloseAllCommand |
false |
手動フラグ – すべてのオープンポジションを即座にクローズします。自動的にリセットされます。 |
使用上の注意
- この戦略では、正確なリスク計算のために、有効な
Step、StepPrice、および VolumeStep メタデータを備えた接続されたポートフォリオとセキュリティが必要です。
- コマンドは終了したローソク足で評価されるため、手動パラメータを切り替えた後に新しいバー (またはローソク足の更新) を受信する必要があります。
- 高度な距離を使用する場合は、
AdvancedStopPips と AdvancedTakeProfitPips の両方が入力されていることを確認してください。それ以外の場合は、ATR ベースのデフォルトが有効のままになります。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// NNFX Auto Trade strategy: ATR-based trend following with EMA filter.
/// Enters on EMA direction with ATR-based trailing stop management.
/// </summary>
public class NnfxAutoTradeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _entryPrice;
private decimal _bestPrice;
private bool _wasBullish;
private bool _hasPrevSignal;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public NnfxAutoTradeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Indicators");
_atrMultiplier = Param(nameof(AtrMultiplier), 2.5m)
.SetDisplay("ATR Multiplier", "ATR multiplier for stop", "Risk");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 12)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_bestPrice = 0m;
_wasBullish = false;
_hasPrevSignal = false;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_bestPrice = 0;
_hasPrevSignal = false;
_candlesSinceTrade = SignalCooldownCandles;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var stopDist = atrValue * AtrMultiplier;
var isBullish = close > emaValue;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
// Trailing stop check
if (Position > 0)
{
if (close > _bestPrice) _bestPrice = close;
if (_bestPrice - close > stopDist)
{
SellMarket();
_entryPrice = 0;
_bestPrice = 0;
_candlesSinceTrade = 0;
return;
}
}
else if (Position < 0)
{
if (close < _bestPrice) _bestPrice = close;
if (close - _bestPrice > stopDist)
{
BuyMarket();
_entryPrice = 0;
_bestPrice = 0;
_candlesSinceTrade = 0;
return;
}
}
// Entry signals
if (_hasPrevSignal && isBullish != _wasBullish && _candlesSinceTrade >= SignalCooldownCandles)
{
if (isBullish && Position <= 0)
{
BuyMarket();
_entryPrice = close;
_bestPrice = close;
_candlesSinceTrade = 0;
}
else if (!isBullish && Position >= 0)
{
SellMarket();
_entryPrice = close;
_bestPrice = close;
_candlesSinceTrade = 0;
}
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
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, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class nnfx_auto_trade_strategy(Strategy):
def __init__(self):
super(nnfx_auto_trade_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(120)))
self._ema_period = self.Param("EmaPeriod", 100)
self._atr_period = self.Param("AtrPeriod", 14)
self._atr_multiplier = self.Param("AtrMultiplier", 2.5)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 12)
self._entry_price = 0.0
self._best_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
self._candles_since_trade = 12
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atr_period.Value = value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
@AtrMultiplier.setter
def AtrMultiplier(self, value):
self._atr_multiplier.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(nnfx_auto_trade_strategy, self).OnReseted()
self._entry_price = 0.0
self._best_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(nnfx_auto_trade_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._best_price = 0.0
self._has_prev_signal = False
self._candles_since_trade = self.SignalCooldownCandles
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, atr, self._process_candle).Start()
def _process_candle(self, candle, ema_value, atr_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
stop_dist = float(atr_value) * float(self.AtrMultiplier)
is_bullish = close > float(ema_value)
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
# Trailing stop check
if self.Position > 0:
if close > self._best_price:
self._best_price = close
if self._best_price - close > stop_dist:
self.SellMarket()
self._entry_price = 0.0
self._best_price = 0.0
self._candles_since_trade = 0
return
elif self.Position < 0:
if close < self._best_price:
self._best_price = close
if close - self._best_price > stop_dist:
self.BuyMarket()
self._entry_price = 0.0
self._best_price = 0.0
self._candles_since_trade = 0
return
# Entry signals
if self._has_prev_signal and is_bullish != self._was_bullish and self._candles_since_trade >= self.SignalCooldownCandles:
if is_bullish and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
self._best_price = close
self._candles_since_trade = 0
elif not is_bullish and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._best_price = close
self._candles_since_trade = 0
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return nnfx_auto_trade_strategy()