エントリーロジック
スキャン
DynamicScanner
class DynamicScanner:
"""動的銘柄スキャナー"""
def scan(self) -> list[HotSymbol]:
"""ホットシンボルをスキャン"""
hot_symbols = []
for symbol in self.universe:
# 1. UWフロー確認
flows = self.uw_client.get_flows(symbol)
# 2. GEXプロファイル取得
gex = self.gex_engine.calculate(symbol)
# 3. IV Rank取得
iv_rank = self.iv_provider.get_iv_rank(symbol)
# 4. ホット判定
if self._is_hot(flows, gex, iv_rank):
hot_symbols.append(HotSymbol(symbol, flows, gex, iv_rank))
return hot_symbols
フィルタ条件
5条件チェック
graph TD
A[候補銘柄] --> B{1. UW Sweep?}
B -->|No| X[スキップ]
B -->|Yes| C{2. GEXマッチ?}
C -->|No| X
C -->|Yes| D{3. IV Rank範囲内?}
D -->|No| X
D -->|Yes| E{4. モメンタム?}
E -->|No| X
E -->|Yes| F{5. リスク枠?}
F -->|No| X
F -->|Yes| G[エントリー候補]
条件詳細
| 条件 |
Spear |
Shield |
| UW Sweep |
必須 |
不要 |
| GEXマッチ |
必須 |
必須 |
| IV Rank |
30-70 |
50+ |
| モメンタム |
必須 |
反転シグナル |
| リスク枠 |
15%以下 |
8%以下 |
エントリー
ストライク選定
def select_strikes(
chain: OptionChain,
direction: str,
spread_width: float
) -> tuple[float, float]:
"""ストライクを選定"""
atm = chain.get_atm_strike()
if direction == "CALL":
# Call Credit Spread
sell_strike = atm + 1 # ATM+1
buy_strike = sell_strike + spread_width
else:
# Put Credit Spread
sell_strike = atm - 1 # ATM-1
buy_strike = sell_strike - spread_width
return sell_strike, buy_strike
DTE選定
def select_expiration(
chain: OptionChain,
target_dte_min: int,
target_dte_max: int
) -> date:
"""満期日を選定"""
expirations = chain.get_expirations()
for exp in expirations:
dte = (exp - date.today()).days
if target_dte_min <= dte <= target_dte_max:
return exp
return None
数量計算
def calculate_quantity(
capital: float,
risk_percent: float,
spread_width: float
) -> int:
"""数量を計算"""
risk_amount = capital * risk_percent
max_loss_per_contract = spread_width * 100
return int(risk_amount / max_loss_per_contract)
注文発注
Limit Order
def place_entry_order(
symbol: str,
sell_strike: float,
buy_strike: float,
expiration: date,
option_type: str,
quantity: int
) -> Order:
"""エントリー注文を発注"""
# クレジット計算
sell_option = get_option(symbol, sell_strike, expiration, option_type)
buy_option = get_option(symbol, buy_strike, expiration, option_type)
credit = sell_option.bid - buy_option.ask
limit_price = credit * 0.95 # 5%マージン
# スプレッド注文
order = ComboOrder(
legs=[
OrderLeg(sell_option, "SELL", quantity),
OrderLeg(buy_option, "BUY", quantity),
],
order_type="LMT",
limit_price=limit_price,
tif="DAY"
)
return ibkr.place_order(order)
フィルタ追跡(v2.5)
FilterTracker統合
v2.5から、各フィルタ段階での通過/振り落とし状況を自動追跡します。
from core.filter_tracker import FilterTracker, FilterStageType
tracker = FilterTracker.instance()
# 各段階での判定を記録
tracker.record_filter_result(
symbol="NVDA",
target_date=date.today(),
stage=FilterStageType.MOMENTUM.value,
passed=False,
reason="score=0.35 < 0.50",
trade_id="abc123",
snapshot=market_snapshot,
)
追跡される段階
| 段階 |
説明 |
振り落とし例 |
| OPTION_CHAIN |
チェーン利用可能 |
no_option_chain |
| UW_SWEEP |
Sweep検知 |
no_sweep_detected |
| GEX_MATCH |
レジームマッチ |
not_gex_valley |
| IV_RANK |
IV範囲内 |
iv_rank=0.25<0.30 |
| MOMENTUM |
モメンタム条件 |
score=0.35<0.50 |
| RISK_BUDGET |
リスク枠 |
quantity=0 |
| SPREAD_BUILD |
構築成功 |
spread_build_failed |
サマリー取得
# ダッシュボード用サマリー
stats = tracker.get_summary()
# 出力例
{
"entry_funnel": [
{"name": "OPTION_CHAIN", "passed": 1000, "rejected": 50, "pass_rate": 95.2},
{"name": "MOMENTUM", "passed": 200, "rejected": 800, "pass_rate": 20.0},
...
],
"exit_distribution": [...],
"total_scanned": 1050,
"total_entered": 15,
}
実装ファイル
core/scanner.py - DynamicScanner
core/execution.py - 注文発注
core/filter_tracker.py - フィルタ追跡
strategies/sunacchan_spear.py - Spearエントリー
strategies/beat_shield.py - Shieldエントリー