ロール戦略¶
概要¶
ポジションを次の満期に移行(ロール)する戦略です。
ロール条件¶
1. ITMロール¶
def check_itm_roll(position: Position) -> bool:
"""ITMロール条件をチェック"""
underlying_price = get_underlying_price(position.symbol)
if position.option_type == "PUT":
# Put Credit Spread
return underlying_price < position.sell_strike
else:
# Call Credit Spread
return underlying_price > position.sell_strike
2. DTEロール¶
DTE_ROLL_THRESHOLD = 7 # 7日以下でロール
def check_dte_roll(position: Position) -> bool:
"""DTEロール条件をチェック"""
dte = (position.expiration - date.today()).days
return dte <= DTE_ROLL_THRESHOLD
3. デルタロール¶
DELTA_ROLL_THRESHOLD = 0.70
def check_delta_roll(position: Position) -> bool:
"""デルタロール条件をチェック"""
return abs(position.sell_delta) > DELTA_ROLL_THRESHOLD
ロールフロー¶
sequenceDiagram
participant PM as PositionMonitor
participant RS as RollStrategy
participant IB as IBKR
participant TS as TradeStore
PM->>RS: Check Roll Conditions
RS-->>PM: Roll Needed
PM->>RS: Generate Roll Order
RS->>RS: Select New Strikes
RS->>RS: Calculate Credit/Debit
RS-->>PM: Roll Order
PM->>IB: Place Roll Order
IB-->>PM: Confirmation
PM->>TS: Record Roll
ロール注文生成¶
def generate_roll_order(position: Position) -> RollOrder:
"""ロール注文を生成"""
# 1. 新しい満期を選択
new_expiration = select_next_expiration(
position.symbol,
target_dte=position.strategy.target_dte
)
# 2. 新しいストライクを選択
new_sell_strike, new_buy_strike = select_strikes(
position.symbol,
new_expiration,
position.option_type,
position.spread_width
)
# 3. クレジット/デビット計算
close_debit = get_spread_price(position) # 現在ポジションを閉じるコスト
open_credit = get_spread_price(new_sell_strike, new_buy_strike) # 新規ポジションのクレジット
net = open_credit - close_debit
return RollOrder(
close_legs=[
OrderLeg(position.sell_option, "BUY", position.quantity),
OrderLeg(position.buy_option, "SELL", position.quantity),
],
open_legs=[
OrderLeg(new_sell_option, "SELL", position.quantity),
OrderLeg(new_buy_option, "BUY", position.quantity),
],
net_credit=net if net > 0 else None,
net_debit=-net if net < 0 else None,
)
ロール実行¶
async def execute_roll(position: Position, roll_order: RollOrder):
"""ロールを実行"""
# 1. 4本足のコンボ注文を発注
result = await ibkr.place_combo_order(
legs=roll_order.close_legs + roll_order.open_legs,
order_type="LMT",
limit_price=roll_order.net_credit or -roll_order.net_debit,
tif="DAY"
)
# 2. トレード記録
trade_store.record_roll(
position_id=position.id,
new_expiration=roll_order.new_expiration,
new_strikes=(roll_order.new_sell_strike, roll_order.new_buy_strike),
net_credit=roll_order.net_credit,
net_debit=roll_order.net_debit,
)
# 3. ポジション更新
position.update(
expiration=roll_order.new_expiration,
sell_strike=roll_order.new_sell_strike,
buy_strike=roll_order.new_buy_strike,
)
ロール履歴追跡¶
class RollHistory:
"""ロール履歴"""
def record(self, position_id: str, roll_details: dict):
"""ロールを記録"""
self.rolls.append({
"position_id": position_id,
"timestamp": datetime.now(),
"old_expiration": roll_details["old_expiration"],
"new_expiration": roll_details["new_expiration"],
"old_strikes": roll_details["old_strikes"],
"new_strikes": roll_details["new_strikes"],
"net_credit": roll_details["net_credit"],
"net_debit": roll_details["net_debit"],
"reason": roll_details["reason"],
})
def get_roll_count(self, position_id: str) -> int:
"""ロール回数を取得"""
return len([r for r in self.rolls if r["position_id"] == position_id])
実装ファイル¶
strategies/roll_strategy.py- ロール戦略core/execution.py- ロール注文発注