ペアトレーディング戦略

概要

PairsTradingStrategy は、関連する 2 つの銘柄間の統計的裁定に基づくペアトレーディング戦略です。2 つの資産価格のスプレッドを追跡し、スプレッドが平均から大きく乖離したときに、平均回帰を期待してポジションを建てます。

主要コンポーネント

この戦略は Strategy を継承し、設定にパラメーターを使用します。

public class PairsTradingStrategy : Strategy
{
	private readonly StrategyParam<int> _spreadLength;
	private readonly StrategyParam<decimal> _entryThreshold;
	private readonly StrategyParam<decimal> _exitThreshold;
	private readonly StrategyParam<DataType> _candleType;

	// 各銘柄の最新価格
	private decimal? _lastPrice1;
	private decimal? _lastPrice2;
}

戦略パラメーター

この戦略では、次のパラメーターをカスタマイズできます。

  • SpreadLength - スプレッドの平均と標準偏差を計算する期間(既定値は 20)
  • EntryThreshold - ポジションにエントリーするための Z-Score しきい値(既定値は 2.0)
  • ExitThreshold - ポジションを決済するための Z-Score しきい値(既定値は 0.5)
  • CandleType - 使用するローソク足タイプ(既定値は 5 分)

すべてのパラメーターは、指定された値範囲で最適化に使用できます。

戦略の初期化

OnStarted2 メソッドで、インジケーターが作成され、2 つの銘柄のローソク足購読が設定されます。

protected override void OnStarted2(DateTime time)
{
	base.OnStarted2(time);

	// ペアトレーディング用に 2 つの銘柄を取得
	var securities = GetWorkingSecurities().ToArray();
	if (securities.Length < 2)
		throw new InvalidOperationException("2つの銘柄を指定する必要があります。");

	var sec1 = securities[0].sec;
	var sec2 = securities[1].sec;

	// スプレッドの平均と標準偏差を計算するインジケーター
	var sma = new SimpleMovingAverage { Length = SpreadLength };
	var stdDev = new StandardDeviation { Length = SpreadLength };

	_lastPrice1 = null;
	_lastPrice2 = null;

	// 1 つ目の銘柄のローソク足を購読
	SubscribeCandles(CandleType, security: sec1)
		.Bind(c =>
		{
			if (c.State != CandleStates.Finished)
				return;

			_lastPrice1 = c.ClosePrice;
		})
		.Start();

	// スプレッド処理を含めて 2 つ目の銘柄のローソク足を購読
	SubscribeCandles(CandleType, security: sec2)
		.Bind(c =>
		{
			if (c.State != CandleStates.Finished)
				return;

			_lastPrice2 = c.ClosePrice;

			if (_lastPrice1 == null)
				return;

			ProcessSpread(_lastPrice1.Value, _lastPrice2.Value, sma, stdDev);
		})
		.Start();
}

スプレッド処理

ProcessSpread メソッドは、スプレッドの Z-Score を計算し、取引シグナルを生成します。

private void ProcessSpread(decimal price1, decimal price2,
	SimpleMovingAverage sma, StandardDeviation stdDev)
{
	// 価格差としてスプレッドを計算
	var spread = price1 - price2;

	// インジケーターを処理
	var smaValue = sma.Process(new DecimalIndicatorValue(sma, spread));
	var devValue = stdDev.Process(new DecimalIndicatorValue(stdDev, spread));

	if (!sma.IsFormed || !stdDev.IsFormed)
		return;

	if (!IsFormedAndOnlineAndAllowTrading())
		return;

	var mean = smaValue.ToDecimal();
	var dev = devValue.ToDecimal();

	if (dev == 0)
		return;

	// Z-Score を計算: 平均からのスプレッド乖離を標準偏差単位で表す
	var zScore = (spread - mean) / dev;

	// スプレッドが高すぎる: 1 つ目の銘柄を売り、2 つ目を買う
	if (zScore > EntryThreshold && Position >= 0)
	{
		SellMarket(Volume + Math.Abs(Position));
	}
	// スプレッドが低すぎる: 1 つ目の銘柄を買い、2 つ目を売る
	else if (zScore < -EntryThreshold && Position <= 0)
	{
		BuyMarket(Volume + Math.Abs(Position));
	}
	// 平均への回帰: ポジションを決済
	else if (Math.Abs(zScore) < ExitThreshold && Position != 0)
	{
		ClosePosition();
	}
}

取引ロジック

  • 売りシグナル: スプレッドの Z-Score がエントリーしきい値(既定値 2.0)を上回り、ショートポジションがない場合
  • 買いシグナル: スプレッドの Z-Score が負のエントリーしきい値(既定値 -2.0)を下回り、ロングポジションがない場合
  • ポジション決済: Z-Score の絶対値が決済しきい値(既定値 0.5)を下回り、スプレッドが平均へ回帰していることを示す場合

機能

  • 戦略は GetWorkingSecurities() メソッドで取得した 2 つの銘柄を使用します
  • スプレッドは、2 つの銘柄のローソク足終値の差として計算されます
  • Z-Score は、平均からのスプレッド乖離を正規化するために使用されます
  • 戦略は古典的な平均回帰の考え方を実装します
  • 戦略は確定済みローソク足でのみ動作します
  • 最適な戦略設定を見つけるためのパラメーター最適化がサポートされています