GitHub で見る
シンボルスワップ戦略
シンボル スワップ ストラテジー は、MetaTrader 5 ユーティリティ「シンボル スワップ」の StockSharp ポートです。オリジナルの MQL5 プログラムは、トレーダーが任意のティッカーを入力できるパネルを開き、現在のチャートをそのシンボルに即座に切り替え、最新の時間、OHLC 価格、ティックボリューム、スプレッドを含むコンパクトなデータウィンドウを監視します。この C# 変換は、StockSharp の高レベルのサブスクリプション API にのみ依存しながら、同じ責任を維持します。
行動
- 戦略の開始時に、監視する銘柄が決定されます。最初に
WatchedSecurityId を試行します。フィールドが空の場合は、ランチャーで設定されている Strategy.Security に戻ります。
- 選択した
CandleType のローソク足データは、SubscribeCandles(...) を通じてストリーミングされます。完成したバーは、パネルに表示される始値、高値、安値、終値、およびティックのボリュームを提供します。
- リアルタイムの最良買値/売値は
SubscribeLevel1(...) 経由で届きます。スプレッドは、MQL データ ウィンドウを反映するために、相場が更新されるたびに再計算されます。
- フォーマットされたブロックは戦略ログ (
OutputMode = Log) に書き込まれるか、DrawText(...) を使用してチャート (OutputMode = Chart) にレンダリングされ、MetaTrader からフローティング パネルが再作成されます。
- 実行中に
SwapSecurity("TICKER") を呼び出すと、SecurityProvider.LookupById を通じて新しいセキュリティが解決され、ローソク足とレベル 1 フィードの両方が要求された商品にシームレスに再サブスクライブされます。
この戦略は情報提供のみを目的としています。注文はしません。マーケットダッシュボードとしてスタンドアロンで実行することも、他の取引ボットと並行して実行することもできます。
パラメーター
| 名前 |
説明 |
デフォルト |
CandleType |
OHLC とティックボリュームデータの構築に使用されるローソク足のサブスクリプションを定義する時間枠。 |
TimeFrame(1 minute) |
WatchedSecurityId |
オプションの機器識別子。 Strategy.Security を使用するには、空のままにしておきます。 |
空 |
OutputMode |
情報ブロックのレンダリング先。 Chart (価格付近のオーバーレイ) または Log (戦略ログ) のいずれかを選択します。 |
Chart |
パブリックメソッド
| 方法 |
説明 |
SwapSecurity(string securityId) |
アクティブな SecurityProvider を通じて提供されたティッカーを解決し、すぐにパネルをそのシンボルに切り替えます。このメソッドは複数回呼び出すことができます。各呼び出しでは、新しいフィードを追加する前に、以前のキャンドル/レベル 1 サブスクリプションがクリアされます。 |
使用上の注意
- コネクタが要求された識別子を公開していることを確認してください。それ以外の場合、
SecurityProvider.LookupById は例外をスローします。
OutputMode = Chart の場合、ストラテジーは自動的にチャート領域を作成し、登録されたローソク足を描画し、ステータス ブロックをオーバーレイします。ログ モードの場合は、テキスト更新のみが生成されます。
- ティックの量はローソク足の
TotalVolume と等しくなります。これにより、MetaTrader はバーごとのティック数を報告します。
- スプレッドは、ベストビッドとベストアスクの両方が利用可能な場合にのみ表示されます。それ以外の場合、フィールドには
n/a が表示されます。
変換の詳細
- MetaTrader タイマー ループは StockSharp サブスクリプションに置き換えられます。ローソク足は完成したバーごとに 1 回トリガーされ、レベル 1 相場はスプレッドをリアルタイムで更新します。
- MQL パネルのラベルは、単一の複数行のテキスト ブロックで表されます。テキストでは、元のツールの正確な順序 (時間、期間、シンボル、終値、始値、高値、安値、ティックボリューム、スプレッド) が使用されています。
- ランタイム シンボル スワップでは、手動による Market Watch 管理はもう必要ありません。この戦略は、StockSharp セキュリティ プロバイダーを介して商品を直接解決します。
- 高レベルの API 呼び出しのみが使用されます (
SubscribeCandles、SubscribeLevel1、DrawText、AddInfo)。リポジトリのコーディング ルールを満たすため、手動のインジケーターの計算や直接のコネクタ操作はありません。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Market monitoring strategy that tracks price metrics and trades on significant
/// spread changes. Simplified from the MetaTrader "Symbol Swap" display panel.
/// </summary>
public class SymbolSwapStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<decimal> _spreadThreshold;
private SimpleMovingAverage _sma;
private decimal _entryPrice;
/// <summary>
/// Candle type for monitoring.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// SMA period for trend detection.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
/// <summary>
/// Price deviation threshold for entry signals.
/// </summary>
public decimal SpreadThreshold
{
get => _spreadThreshold.Value;
set => _spreadThreshold.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public SymbolSwapStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle series for signals", "General");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Moving average period", "Indicators");
_spreadThreshold = Param(nameof(SpreadThreshold), 3m)
.SetGreaterThanZero()
.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_entryPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaPeriod };
SubscribeCandles(CandleType)
.Bind(_sma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormed)
return;
var price = candle.ClosePrice;
// Exit on mean reversion
if (Position != 0 && _entryPrice > 0m)
{
var pnl = Position > 0
? price - _entryPrice
: _entryPrice - price;
// Exit on profit or loss threshold
if (pnl >= SpreadThreshold || pnl <= -SpreadThreshold * 2m)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
else
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
return;
}
}
// Entry on deviation
if (Position == 0)
{
var deviation = price - smaValue;
if (deviation > SpreadThreshold)
{
SellMarket();
_entryPrice = price;
}
else if (deviation < -SpreadThreshold)
{
BuyMarket();
_entryPrice = price;
}
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class symbol_swap_strategy(Strategy):
def __init__(self):
super(symbol_swap_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle series for signals", "General")
self._sma_period = self.Param("SmaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("SMA Period", "Moving average period", "Indicators")
self._spread_threshold = self.Param("SpreadThreshold", 3.0) \
.SetGreaterThanZero() \
.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals")
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
@property
def SpreadThreshold(self):
return self._spread_threshold.Value
@SpreadThreshold.setter
def SpreadThreshold(self, value):
self._spread_threshold.Value = value
def OnReseted(self):
super(symbol_swap_strategy, self).OnReseted()
self._entry_price = 0.0
def OnStarted2(self, time):
super(symbol_swap_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.SmaPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(sma, self._process_candle) \
.Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormed:
return
price = float(candle.ClosePrice)
sma_v = float(sma_value)
threshold = float(self.SpreadThreshold)
# Exit on mean reversion
if self.Position != 0 and self._entry_price > 0:
pnl = price - self._entry_price if self.Position > 0 else self._entry_price - price
if pnl >= threshold or pnl <= -threshold * 2:
if self.Position > 0:
self.SellMarket(abs(self.Position))
else:
self.BuyMarket(abs(self.Position))
self._entry_price = 0.0
return
# Entry on deviation
if self.Position == 0:
deviation = price - sma_v
if deviation > threshold:
self.SellMarket()
self._entry_price = price
elif deviation < -threshold:
self.BuyMarket()
self._entry_price = price
def CreateClone(self):
return symbol_swap_strategy()