アービトラージ ストラテジー
概要
ArbitrageStrategy は、先物コントラクトとその原資産の間のアービトラージ ストラテジーです。銘柄間のスプレッドを追跡し、アービトラージ機会が発生したときにポジションを開きます。
主なコンポーネント
このストラテジーは Strategy から継承し、設定にパラメーターを使用します。
public class ArbitrageStrategy : Strategy
{
private enum ArbitrageState
{
Contango, // 先物価格が原資産より高い
Backwardation, // 原資産価格が先物より高い
None, // ポジションなし
OrderRegistration // 注文登録中
}
// ストラテジー パラメーター
private readonly StrategyParam<Security> _futureSecurity;
private readonly StrategyParam<Security> _stockSecurity;
private readonly StrategyParam<Portfolio> _futurePortfolio;
private readonly StrategyParam<Portfolio> _stockPortfolio;
private readonly StrategyParam<decimal> _stockMultiplicator;
private readonly StrategyParam<decimal> _futureVolume;
private readonly StrategyParam<decimal> _stockVolume;
private readonly StrategyParam<decimal> _profitToExit;
private readonly StrategyParam<decimal> _spreadToGenerateSignal;
}
ストラテジー パラメーター
このストラテジーでは、次のパラメーターをカスタマイズできます。
- FutureSecurity - 先物銘柄
- StockSecurity - 原資産銘柄
- FuturePortfolio - 先物取引用ポートフォリオ
- StockPortfolio - 原資産取引用ポートフォリオ
- StockMultiplicator - 原資産の乗数 (例: ロット サイズ)
- FutureVolume - 先物取引の数量
- StockVolume - 原資産取引の数量
- ProfitToExit - ポジション退出の利益しきい値
- SpreadToGenerateSignal - エントリー シグナル生成のスプレッドしきい値
ストラテジーの初期化
OnStarted2 メソッドでは、パラメーターが検証され、オーダーブックと自己約定へのサブスクリプションが作成されます。
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (FutureSecurity == null)
throw new InvalidOperationException("先物銘柄が指定されていません。");
if (StockSecurity == null)
throw new InvalidOperationException("株式銘柄が指定されていません。");
if (FuturePortfolio == null)
throw new InvalidOperationException("先物ポートフォリオが指定されていません。");
if (StockPortfolio == null)
throw new InvalidOperationException("株式ポートフォリオが指定されていません。");
_futId = FutureSecurity.ToSecurityId();
_stockId = StockSecurity.ToSecurityId();
// 両方の銘柄のオーダーブック更新を購読する
var futureDepthSubscription = new Subscription(DataType.MarketDepth, FutureSecurity);
var stockDepthSubscription = new Subscription(DataType.MarketDepth, StockSecurity);
futureDepthSubscription.WhenOrderBookReceived(this).Do(ProcessMarketDepth).Apply(this);
stockDepthSubscription.WhenOrderBookReceived(this).Do(ProcessMarketDepth).Apply(this);
// 執行価格を追跡するために自己約定を購読する
this
.WhenOwnTradeReceived()
.Do(OnOwnTradeReceived)
.Apply(this);
// マーケット データ購読リクエストを送信する
Subscribe(futureDepthSubscription);
Subscribe(stockDepthSubscription);
}
マーケット データの処理
ProcessMarketDepth メソッドはオーダーブックが更新されたときに呼び出され、主要ロジックを実装します。
private void ProcessMarketDepth(IOrderBookMessage depth)
{
// 各銘柄の直近オーダーブックを更新する
if (depth.SecurityId == _futId)
_lastFut = depth;
else if (depth.SecurityId == _stockId)
_lastSt = depth;
// 両方の銘柄のデータを待つ
if (_lastFut is null || _lastSt is null)
return;
// 指定数量に対する出来高加重平均価格を計算する
_futBid = GetAveragePrice(_lastFut, Sides.Sell, FutureVolume);
_futAck = GetAveragePrice(_lastFut, Sides.Buy, FutureVolume);
_stBid = GetAveragePrice(_lastSt, Sides.Sell, StockVolume) * StockMultiplicator;
_stAsk = GetAveragePrice(_lastSt, Sides.Buy, StockVolume) * StockMultiplicator;
// 価格を検証する
if (_futBid == 0 || _futAck == 0 || _stBid == 0 || _stAsk == 0)
return;
// スプレッドを計算する
var contangoSpread = _futBid - _stAsk; // 先物価格 > 原資産価格
var backwardationSpread = _stBid - _futAck; // 原資産価格 > 先物価格
decimal spread;
ArbitrageState arbitrageSignal;
// 最良のアービトラージ機会を判定する
if (backwardationSpread > contangoSpread)
{
arbitrageSignal = ArbitrageState.Backwardation;
spread = backwardationSpread;
}
else
{
arbitrageSignal = ArbitrageState.Contango;
spread = contangoSpread;
}
// 現在の状態とスプレッドをログに記録する
LogInfo($"Current state {_currentState}, enter spread = {_enterSpread}");
LogInfo($"{ArbitrageState.Backwardation} spread = {backwardationSpread}");
LogInfo($"{ArbitrageState.Contango} spread = {contangoSpread}");
LogInfo($"スプレッドでエントリー:{SpreadToGenerateSignal}。利益で決済:{ProfitToExit}");
// 現在の市場状況に基づいて利益を再計算する
if (_currentState != ArbitrageState.None && _currentState != ArbitrageState.OrderRegistration)
{
CalculateProfit();
LogInfo($"Profit: {_profit}");
}
// 現在の状態と市場状況に基づいてシグナルを処理する
ProcessSignals(arbitrageSignal, spread);
}
取引ロジック
シグナル処理とエントリー/退出判断は、ProcessSignals メソッドに実装されています。
private void ProcessSignals(ArbitrageState arbitrageSignal, decimal spread)
{
// オープン ポジションがなく、スプレッドがしきい値を超えたときに新しいポジションへ入る
if (_currentState == ArbitrageState.None && spread > SpreadToGenerateSignal)
{
_currentState = ArbitrageState.OrderRegistration;
if (arbitrageSignal == ArbitrageState.Backwardation)
{
ExecuteBackwardation();
}
else
{
ExecuteContango();
}
}
// 利益しきい値に到達したとき Backwardation ポジションから退出する
else if (_currentState == ArbitrageState.Backwardation && _profit >= ProfitToExit)
{
_currentState = ArbitrageState.OrderRegistration;
CloseBackwardationPosition();
}
// 利益しきい値に到達したとき Contango ポジションから退出する
else if (_currentState == ArbitrageState.Contango && _profit >= ProfitToExit)
{
_currentState = ArbitrageState.OrderRegistration;
CloseContangoPosition();
}
}
利益計算
CalculateProfit メソッドは、エントリー価格と現在価格に基づいて現在の利益を計算します。
private void CalculateProfit()
{
switch (_currentState)
{
case ArbitrageState.Backwardation:
// 先物を買い、原資産を売る - 先物価格が上昇し、原資産価格が下落すると利益
_profit = (_stockExitPrice * StockMultiplicator - _stAsk) + (_futBid - _futureBuyPrice);
break;
case ArbitrageState.Contango:
// 先物を売り、原資産を買う - 先物価格が下落し、原資産価格が上昇すると利益
_profit = (_futureExitPrice - _futAck) + (_stBid - _stockBuyPrice * StockMultiplicator);
break;
default:
_profit = 0;
break;
}
}
注文生成
アービトラージ ストラテジーを実行するために、注文を生成するメソッドが使用されます。
private (Order buy, Order sell) GenerateOrdersBackwardation()
{
var futureBuy = CreateOrder(Sides.Buy, FutureVolume);
futureBuy.Portfolio = FuturePortfolio;
futureBuy.Security = FutureSecurity;
futureBuy.Type = OrderTypes.Market;
var stockSell = CreateOrder(Sides.Sell, StockVolume);
stockSell.Portfolio = StockPortfolio;
stockSell.Security = StockSecurity;
stockSell.Type = OrderTypes.Market;
return (futureBuy, stockSell);
}
private (Order sell, Order buy) GenerateOrdersContango()
{
var futureSell = CreateOrder(Sides.Sell, FutureVolume);
futureSell.Portfolio = FuturePortfolio;
futureSell.Security = FutureSecurity;
futureSell.Type = OrderTypes.Market;
var stockBuy = CreateOrder(Sides.Buy, StockVolume);
stockBuy.Portfolio = StockPortfolio;
stockBuy.Security = StockSecurity;
stockBuy.Type = OrderTypes.Market;
return (futureSell, stockBuy);
}
特徴
- このストラテジーは 2 つの異なる銘柄と 2 つのポートフォリオでの動作をサポートします
- 迅速な執行のために成行注文が使用されます
- 注文執行の追跡にはルール (IMarketRule) が使用されます
- より正確な価格のために、数量に基づく出来高加重平均価格が計算されます
- アービトラージ ロジックは、順方向 (contango) と逆方向 (backwardation) の両方のスプレッドを考慮します
- 目標しきい値に到達したときの自動利益計算と退出をサポートします