26 KiB
Trading Playbook Implementation Suggestions
Current State Analysis
✅ What You Already Have
- Badge system: 🟢/🔴, 💎, ⭐, 💰, ⚡, 🚀
- Rocket scoring algorithm
- Price context: RTH open, prior close, 5m/15m momentum
- Tape alignment detection
- Trade signal generation
- Session bucketing (PRE/RTH/POST)
- Premium filtering and aggregations
❌ What's Missing (High Impact)
PART A — TRADING LOGIC ENHANCEMENTS
1️⃣ Signal Tier Classification System
Current Gap: All signals are treated equally. You need to classify them into Tier-1, Tier-2, and Ignore categories.
Suggestion:
- Add a new service:
backend/python_service/services/signal_tier_classifier.py- Classify signals based on badge combinations
- Tier-1: 🟢/🔴 + 💎 + ⭐ + premium > 500K + direction aligned
- Tier-2: 🟢 + 💎 (no ⭐) OR ⭐ without 💎
- Ignore: OTM-only, mixed signals, low volume/OI ratio
Implementation Approach:
# In options_flow_processor.py, add after process_badges():
def classify_signal_tier(row):
badge_round = row.get('badge_round', '')
badge_more = row.get('badge_more', '')
premium = row.get('premium_num', 0) or 0
direction = row.get('direction', '')
bull_total = row.get('bull_total', 0) or 0
bear_total = row.get('bear_total', 0) or 0
has_diamond = '💎' in badge_more
has_star = '⭐' in badge_more
# Tier-1 conditions
if (badge_round in ['🟢', '🔴'] and
has_diamond and has_star and
premium > 500000):
# Check direction alignment
if (badge_round == '🟢' and direction == 'BULL' and (bull_total - bear_total) > 0):
return 'TIER_1'
elif (badge_round == '🔴' and direction == 'BEAR' and (bear_total - bull_total) > 0):
return 'TIER_1'
# Tier-2 conditions
if (badge_round == '🟢' and has_diamond and not has_star):
return 'TIER_2'
if (has_star and not has_diamond):
return 'TIER_2'
# Ignore conditions
# (Add logic for OTM-only, mixed signals, etc.)
return 'IGNORE'
Database Addition:
- Add
signal_tiercolumn to processed flow output - Add
is_tradeableboolean flag
2️⃣ VWAP Integration
Current Gap: You have price context but no VWAP calculation or VWAP-based entry/exit logic.
Suggestion:
- Extend:
backend/python_service/services/price_context.py- Add
calculate_vwap()method - Calculate VWAP for each symbol on each trading day
- Store VWAP at signal time
- Calculate distance from VWAP (percentage)
- Add
Implementation Approach:
# Add to PriceContextService:
async def get_vwap_at_time(self, symbol: str, timestamp: datetime, pool: asyncpg.Pool):
"""Calculate VWAP up to the given timestamp for the trading day"""
# Query all 1m bars from RTH open to timestamp
# Calculate: SUM(price * volume) / SUM(volume)
# Return VWAP value and distance from current price
New Fields to Add:
vwap_at_signal- VWAP value at signal timeprice_vs_vwap_pct- Percentage distance from VWAPvwap_reclaimed- Boolean: did price reclaim VWAP after signal?
Entry Strategy Integration:
- Best entry: VWAP pullback or VWAP reclaim
- Good entry: Break & hold above prior high
- Avoid: Chasing vertical candles
3️⃣ Price Reaction Tracking (MOST IMPORTANT)
Current Gap: No tracking of how price moves AFTER the signal appears.
Suggestion:
- New service:
backend/python_service/services/price_reaction_tracker.py- Track price 5 minutes, 15 minutes, 30 minutes after signal
- Calculate price change percentage
- Identify if flow led to price movement or was just hedging
Implementation Approach:
class PriceReactionTracker:
async def track_reaction(self, flow_row, pool):
signal_time = flow_row['flow_ts_utc']
symbol = flow_row['symbol_norm']
price_at_signal = flow_row['u_close']
# Get price 5m, 15m, 30m after signal
price_5m = await get_price_at_time(symbol, signal_time + timedelta(minutes=5))
price_15m = await get_price_at_time(symbol, signal_time + timedelta(minutes=15))
price_30m = await get_price_at_time(symbol, signal_time + timedelta(minutes=30))
# Calculate reactions
reaction_5m = ((price_5m - price_at_signal) / price_at_signal) * 100 if price_5m else None
reaction_15m = ((price_15m - price_at_signal) / price_at_signal) * 100 if price_15m else None
reaction_30m = ((price_30m - price_at_signal) / price_at_signal) * 100 if price_30m else None
# High/Low break confirmation
high_break = price_5m > flow_row.get('u_high', 0)
low_break = price_5m < flow_row.get('u_low', 0)
return {
'price_reaction_5m_pct': reaction_5m,
'price_reaction_15m_pct': reaction_15m,
'price_reaction_30m_pct': reaction_30m,
'high_break_5m': high_break,
'low_break_5m': low_break,
'flow_led_to_move': reaction_5m and abs(reaction_5m) > 0.5 # 0.5% threshold
}
Database Addition:
- Add columns:
price_reaction_5m_pct,price_reaction_15m_pct,high_break_5m,low_break_5m - Add flag:
flow_led_to_move(boolean)
Why This Matters:
- Flow without price reaction = hedge or roll (ignore)
- Flow with price reaction = real positioning (trade it)
4️⃣ Strike Clustering Detection
Current Gap: No detection of multiple large trades at the same strike (institutional layering).
Suggestion:
- New service:
backend/python_service/services/strike_cluster_detector.py- Group trades by strike and expiration
- Identify clusters: 3+ trades at same strike within 30 minutes
- Calculate cluster premium total
- Flag as "institutional positioning" vs "single trade"
Implementation Approach:
class StrikeClusterDetector:
def detect_clusters(self, df: pd.DataFrame, window_minutes: int = 30):
"""Detect strike clusters within time window"""
df = df.copy()
# Group by symbol, exp_date, strike
clusters = df.groupby(['symbol_norm', 'exp_date', 'strike_num']).apply(
lambda g: self._find_clusters_in_group(g, window_minutes)
)
return clusters
def _find_clusters_in_group(self, group, window_minutes):
"""Find time-based clusters within a strike group"""
# Sort by time
group = group.sort_values('flow_ts_utc')
# Rolling window: if 3+ trades within window_minutes, it's a cluster
# Return cluster flags and cluster IDs
New Fields:
is_cluster_trade- Booleancluster_id- Unique ID for the clustercluster_size- Number of trades in clustercluster_total_premium- Sum of all premiums in cluster
Why This Matters:
- Institutions rarely place one order — they layer
- Clusters = stronger signal than single prints
5️⃣ Gamma Exposure (GEX) Calculation
Current Gap: No gamma exposure tracking. This explains why some rockets fail.
Suggestion:
- New service:
backend/python_service/services/gamma_calculator.py- Calculate call GEX and put GEX per strike
- Net dealer gamma = Call GEX - Put GEX
- Positive GEX = price pinned (resistance)
- Negative GEX = explosive moves possible
Implementation Approach:
class GammaCalculator:
def calculate_gex(self, df: pd.DataFrame):
"""
Calculate Gamma Exposure (GEX)
GEX = OI * Spot^2 * Gamma * 0.01 * Multiplier
Simplified: GEX ≈ OI * Spot^2 * 0.01 (for rough estimate)
"""
# For each strike, calculate:
# - Call GEX (positive for calls)
# - Put GEX (negative for puts)
# - Net GEX = Call GEX + Put GEX
# Add to flow row:
# - strike_gex (GEX at this strike)
# - net_dealer_gex (aggregate GEX for symbol)
# - gex_pin_level (strike with highest GEX)
New Fields:
strike_gex- GEX at this strikenet_dealer_gex- Net GEX for the symbolgex_pin_level- Strike where GEX is highest (pin level)is_gex_positive- Boolean: positive GEX = pinning, negative = explosive
Why This Matters:
- +GEX = Price pinned (rockets may fail at pin level)
- -GEX = Explosive moves (rockets more likely to work)
6️⃣ Delta Weighting (Smart Money Filter)
Current Gap: No delta weighting. ITM delta > OTM lottery tickets.
Suggestion:
- Extend:
backend/python_service/services/options_flow_processor.py- Add delta calculation (approximate: use Black-Scholes or simplified formula)
- Calculate:
delta_weighted_premium = delta * volume * premium - Filter out low delta-weighted trades (YOLO prints)
Implementation Approach:
def calculate_delta_weighted_value(row):
"""Calculate delta-weighted premium value"""
# Simplified delta approximation:
# For CALL: delta ≈ N(d1) where d1 = (ln(S/K) + (r+σ²/2)*T) / (σ*√T)
# For rough estimate: delta ≈ 0.5 for ATM, 0.8+ for ITM, 0.2- for OTM
spot = row.get('spot_num', 0)
strike = row.get('strike_num', 0)
cp = row.get('cp_norm', '')
moneyness = row.get('moneyness', '')
# Simplified delta based on moneyness
if moneyness == 'ITM':
delta = 0.7 if cp == 'CALL' else 0.7
elif moneyness == 'OTM':
delta = 0.3 if cp == 'CALL' else 0.3
else: # ATM
delta = 0.5
volume = row.get('vol_num', 0) or 0
premium = row.get('premium_num', 0) or 0
return delta * volume * premium
New Fields:
delta_approx- Approximate delta valuedelta_weighted_premium- Delta * Volume * Premiumis_smart_money- Boolean: delta_weighted_premium > threshold
Why This Matters:
- Filters out YOLO OTM lottery prints
- ITM delta > OTM = real positioning
7️⃣ Time-to-Expiration Buckets
Current Gap: No DTE-based classification.
Suggestion:
- Extend:
backend/python_service/services/options_flow_processor.py- Calculate DTE (days to expiration)
- Bucket into: 0DTE, 1-3 DTE, 7-14 DTE, Monthly
- Different logic per bucket
Implementation Approach:
def calculate_dte_bucket(row):
"""Calculate days to expiration and bucket"""
exp_date = row.get('exp_date')
flow_date = row.get('flow_date_cst')
if not exp_date or not flow_date:
return None
if isinstance(flow_date, datetime):
flow_date = flow_date.date()
if isinstance(exp_date, datetime):
exp_date = exp_date.date()
dte = (exp_date - flow_date).days
if dte == 0:
return '0DTE'
elif 1 <= dte <= 3:
return '1-3DTE'
elif 4 <= dte <= 6:
return '4-6DTE'
elif 7 <= dte <= 14:
return '7-14DTE'
elif 15 <= dte <= 30:
return 'MONTHLY'
else:
return 'LONG_TERM'
New Fields:
dte- Days to expirationdte_bucket- Bucket classificationis_0dte- Boolean flag
Why This Matters:
- 0DTE → intraday pressure (gamma risk)
- Longer DTE → directional thesis (less gamma risk)
8️⃣ Sweep vs Block Detection
Current Gap: No distinction between sweeps (urgency) and blocks (positioning).
Suggestion:
- New service:
backend/python_service/services/trade_type_detector.py- Detect multiple trades at same strike/expiration within 2 seconds = SWEEP
- Single large trade = BLOCK
- Different trading implications
Implementation Approach:
class TradeTypeDetector:
def detect_trade_type(self, df: pd.DataFrame):
"""Detect if trade is sweep or block"""
df = df.copy()
df = df.sort_values(['symbol_norm', 'exp_date', 'strike_num', 'flow_ts_utc'])
# Group by symbol, exp, strike
groups = df.groupby(['symbol_norm', 'exp_date', 'strike_num'])
def classify_group(group):
# If multiple trades within 2 seconds = sweep
# If single large trade = block
# Otherwise = regular trade
if len(group) == 1:
return 'BLOCK' if group.iloc[0]['premium_num'] > 500000 else 'REGULAR'
# Check time differences
time_diffs = group['flow_ts_utc'].diff().dt.total_seconds()
has_sweep = (time_diffs <= 2).any()
if has_sweep:
return 'SWEEP'
else:
return 'CLUSTER'
df['trade_type'] = groups.apply(classify_group).values
return df
New Fields:
trade_type- 'SWEEP', 'BLOCK', 'CLUSTER', 'REGULAR'is_sweep- Booleanis_block- Boolean
Why This Matters:
- Sweeps = urgency (institutions hitting multiple exchanges)
- Blocks = positioning (single large order)
9️⃣ Historical Win Rate Tracking
Current Gap: No tracking of which patterns actually work.
Suggestion:
- New service:
backend/python_service/services/pattern_analyzer.py- Track pattern → outcome mapping
- Calculate win rate per pattern
- Average return per pattern
- Max drawdown per pattern
Database Addition:
- New table:
signal_patterns_history- Columns: pattern_hash, signal_time, price_at_signal, price_5m_after, price_15m_after, outcome, return_pct
Implementation Approach:
class PatternAnalyzer:
def track_pattern(self, flow_row, price_reaction):
"""Track pattern and outcome"""
pattern_hash = self._hash_pattern(flow_row)
# Store in database:
# - Pattern signature (badge combo + premium tier + DTE)
# - Outcome (price reaction)
# - Return percentage
def get_pattern_stats(self, pattern_hash):
"""Get historical stats for a pattern"""
# Query database for all instances of this pattern
# Calculate: win_rate, avg_return, max_drawdown
New Fields:
pattern_hash- Unique identifier for patternhistorical_win_rate- Win rate for this patternhistorical_avg_return- Average return for this patternpattern_confidence- Confidence based on historical performance
Why This Matters:
- Discover which patterns actually work
- 🚀🚀 without 💎 fails more often
- 🟢💎⭐ + VWAP reclaim wins most
🔟 Index & Correlation Filter
Current Gap: No SPY/QQQ/VIX alignment check.
Suggestion:
- New service:
backend/python_service/services/index_correlation.py- Fetch SPY/QQQ flow at signal time
- Check VIX direction
- Rule: Single stock flow works best when index agrees
Implementation Approach:
class IndexCorrelationService:
async def check_index_alignment(self, flow_row, pool):
"""Check if index flow aligns with stock flow"""
symbol = flow_row['symbol_norm']
signal_time = flow_row['flow_ts_utc']
direction = flow_row['direction']
# Get SPY/QQQ flow in same time window
spy_flow = await self.get_index_flow('SPY', signal_time, pool)
qqq_flow = await self.get_index_flow('QQQ', signal_time, pool)
# Get VIX direction
vix_direction = await self.get_vix_direction(signal_time, pool)
# Check alignment
index_bullish = (spy_flow.get('net_premium', 0) > 0) or (qqq_flow.get('net_premium', 0) > 0)
index_bearish = (spy_flow.get('net_premium', 0) < 0) or (qqq_flow.get('net_premium', 0) < 0)
aligned = (
(direction == 'BULL' and index_bullish) or
(direction == 'BEAR' and index_bearish)
)
return {
'index_aligned': aligned,
'spy_flow_direction': 'BULL' if spy_flow.get('net_premium', 0) > 0 else 'BEAR',
'qqq_flow_direction': 'BULL' if qqq_flow.get('net_premium', 0) > 0 else 'BEAR',
'vix_direction': vix_direction
}
New Fields:
index_aligned- Boolean: does index flow agree?spy_flow_direction- SPY flow directionqqq_flow_direction- QQQ flow directionvix_direction- VIX direction (up/down)
Why This Matters:
- Single stock flow works best when index agrees
- Contrarian flow (stock vs index) = lower probability
PART B — TRADE CHECKLIST IMPLEMENTATION
Trade Entry Checklist
Suggestion:
- New service:
backend/python_service/services/trade_checklist.py- Implement 5-point checklist
- Return checklist score (0-5)
- Only allow trades with 4/5 or 5/5
Implementation Approach:
class TradeChecklist:
def evaluate(self, flow_row):
"""Evaluate trade checklist"""
checks = {
'has_direction': flow_row.get('badge_round') in ['🟢', '🔴'],
'has_diamond': '💎' in flow_row.get('badge_more', ''),
'has_star': '⭐' in flow_row.get('badge_more', ''),
'price_respects_vwap': self._check_vwap_respect(flow_row),
'index_confirms': flow_row.get('index_aligned', False)
}
score = sum(checks.values())
passed = score >= 4
return {
'checklist_score': score,
'checklist_passed': passed,
'checks': checks
}
New Fields:
checklist_score- 0-5 scorechecklist_passed- Boolean: 4/5 or 5/5checklist_details- JSON with individual check results
PART C — ENHANCED ENTRY/EXIT LOGIC
Entry Strategy Enhancement
Current Gap: Entry logic exists but doesn't use VWAP pullback/reclaim.
Suggestion:
- Extend:
backend/src/services/tradePlanGenerator.js- Add VWAP pullback entry
- Add VWAP reclaim entry
- Add prior high break entry
- Avoid chasing vertical candles
Implementation:
function generateEntryStrategy(signal, currentPrice, priceContext) {
const vwap = priceContext.vwap;
const priorHigh = priceContext.priorHigh;
const vwapDistance = ((currentPrice - vwap) / vwap) * 100;
if (signal === 'BUY') {
// Best: VWAP pullback or VWAP reclaim
if (currentPrice < vwap && vwapDistance > -1) {
return {
type: 'VWAP_PULLBACK',
entry: vwap * 0.998, // Slightly below VWAP
reason: 'VWAP pullback entry'
};
}
// Good: Break & hold above prior high
if (currentPrice > priorHigh) {
return {
type: 'BREAKOUT',
entry: priorHigh * 1.001, // Slightly above prior high
reason: 'Prior high breakout'
};
}
// Avoid: Chasing vertical candles
if (vwapDistance > 2) {
return {
type: 'WAIT',
reason: 'Price too extended from VWAP - wait for pullback'
};
}
}
// Similar for SELL signals...
}
Exit Strategy Enhancement
Current Gap: Exit logic is basic. Need flow-based exits.
Suggestion:
- Extend:
backend/src/services/tradePlanGenerator.js- Exit when flow stalls
- Exit when opposite 💎 appears
- Exit when net premium flips
- Exit when price rejects VWAP
- Scale out at +30-50% option gain
Implementation:
function generateExitStrategy(signal, entryPrice, currentPrice, flowData) {
const exits = [];
// Flow stalls
if (flowData.recentFlowVolume < flowData.avgFlowVolume * 0.3) {
exits.push({
type: 'FLOW_STALL',
reason: 'Flow volume dropped significantly'
});
}
// Opposite diamond appears
if (signal === 'BUY' && flowData.hasBearDiamond) {
exits.push({
type: 'OPPOSITE_SIGNAL',
reason: 'Bear diamond (💎) appeared - exit long'
});
}
// Net premium flips
if (signal === 'BUY' && flowData.netPremium < 0) {
exits.push({
type: 'PREMIUM_FLIP',
reason: 'Net premium flipped negative'
});
}
// Price rejects VWAP
if (currentPrice < priceContext.vwap && signal === 'BUY') {
exits.push({
type: 'VWAP_REJECTION',
reason: 'Price rejected VWAP - exit'
});
}
// Scale out at gains
const gainPct = ((currentPrice - entryPrice) / entryPrice) * 100;
if (gainPct >= 30) {
exits.push({
type: 'SCALE_OUT',
reason: `+${gainPct.toFixed(1)}% gain - scale out 50%`
});
}
return exits;
}
PART D — DATABASE SCHEMA ADDITIONS
New Columns for processed_options_flow (or new enrichment table)
-- Signal classification
signal_tier VARCHAR(10), -- 'TIER_1', 'TIER_2', 'IGNORE'
is_tradeable BOOLEAN,
-- VWAP
vwap_at_signal NUMERIC,
price_vs_vwap_pct NUMERIC,
vwap_reclaimed BOOLEAN,
-- Price reaction
price_reaction_5m_pct NUMERIC,
price_reaction_15m_pct NUMERIC,
price_reaction_30m_pct NUMERIC,
high_break_5m BOOLEAN,
low_break_5m BOOLEAN,
flow_led_to_move BOOLEAN,
-- Strike clustering
is_cluster_trade BOOLEAN,
cluster_id VARCHAR(50),
cluster_size INTEGER,
cluster_total_premium NUMERIC,
-- Gamma exposure
strike_gex NUMERIC,
net_dealer_gex NUMERIC,
gex_pin_level NUMERIC,
is_gex_positive BOOLEAN,
-- Delta weighting
delta_approx NUMERIC,
delta_weighted_premium NUMERIC,
is_smart_money BOOLEAN,
-- DTE
dte INTEGER,
dte_bucket VARCHAR(20),
is_0dte BOOLEAN,
-- Trade type
trade_type VARCHAR(20), -- 'SWEEP', 'BLOCK', 'CLUSTER', 'REGULAR'
is_sweep BOOLEAN,
is_block BOOLEAN,
-- Index correlation
index_aligned BOOLEAN,
spy_flow_direction VARCHAR(10),
qqq_flow_direction VARCHAR(10),
vix_direction VARCHAR(10),
-- Checklist
checklist_score INTEGER,
checklist_passed BOOLEAN,
checklist_details JSONB,
-- Pattern tracking
pattern_hash VARCHAR(100),
historical_win_rate NUMERIC,
historical_avg_return NUMERIC,
pattern_confidence NUMERIC
PART E — IMPLEMENTATION PRIORITY
Phase 1 (Highest Impact - Do First)
- ✅ Price Reaction Tracking - Most important filter
- ✅ VWAP Integration - Critical for entry/exit
- ✅ Signal Tier Classification - Filter noise
- ✅ Trade Checklist - Prevent bad trades
Phase 2 (High Value)
- ✅ Strike Clustering - Identify institutional layering
- ✅ Delta Weighting - Filter YOLO prints
- ✅ Index Correlation - Context filter
Phase 3 (Nice to Have)
- ✅ Gamma Exposure - Explains pinning behavior
- ✅ Sweep vs Block - Trade type classification
- ✅ DTE Buckets - Time-based filtering
Phase 4 (Analytics)
- ✅ Historical Win Rate - Pattern analysis
- ✅ Enhanced Entry/Exit - Refine trading logic
PART F — API ENDPOINT SUGGESTIONS
New Endpoints to Add
-
GET /api/options-flow/enhanced- Returns flow with all new enrichments
- Parameters:
include_price_reaction,include_gex, etc.
-
GET /api/options-flow/checklist- Returns only signals that pass checklist (4/5 or 5/5)
-
GET /api/options-flow/tier-1- Returns only Tier-1 tradeable signals
-
GET /api/patterns/stats- Returns historical win rates per pattern
-
GET /api/options-flow/vwap-analysis- Returns VWAP-based entry opportunities
PART G — FRONTEND DISPLAY SUGGESTIONS
New UI Elements to Add
-
Signal Tier Badge
- Display "TIER-1", "TIER-2", or "IGNORE" badge
- Color code: Green (Tier-1), Yellow (Tier-2), Gray (Ignore)
-
Price Reaction Indicator
- Show 5m/15m price reaction percentage
- Green if positive reaction, Red if negative
- "Flow Led to Move" indicator
-
VWAP Distance Display
- Show current price vs VWAP
- Visual indicator: Above/Below VWAP
- Entry opportunity: "VWAP Pullback" or "VWAP Reclaim"
-
Checklist Score Display
- Show checklist score (X/5)
- Green if passed (4/5+), Red if failed
- Expandable details showing each check
-
Index Alignment Indicator
- Show SPY/QQQ flow direction
- Show if aligned (green) or not (red)
-
Gamma Pin Level
- Display GEX pin level on chart
- Show if price is near pin (resistance)
-
Strike Cluster Visualization
- Show cluster size and total premium
- Highlight clustered strikes
PART H — TESTING SUGGESTIONS
Test Cases to Add
-
Price Reaction Tests
- Test: Flow with no price reaction = should be filtered
- Test: Flow with 5m price reaction = should be tradeable
-
Tier Classification Tests
- Test: 🟢 + 💎 + ⭐ + premium > 500K = Tier-1
- Test: 🟢 + 💎 (no ⭐) = Tier-2
- Test: OTM-only = Ignore
-
Checklist Tests
- Test: 4/5 checks = passed
- Test: 3/5 checks = failed
-
VWAP Tests
- Test: VWAP pullback entry detection
- Test: VWAP reclaim entry detection
SUMMARY
Key Takeaways
- Price Reaction is #1 Priority - This filters out hedges/rolls
- VWAP Integration is Critical - Needed for proper entry/exit
- Tier Classification Reduces Noise - Focus on Tier-1 signals
- Checklist Prevents Bad Trades - Enforce 4/5 minimum
- Strike Clustering Identifies Institutions - Multiple trades = stronger signal
- Index Correlation Adds Context - Single stock works best with index alignment
Implementation Strategy
- Start with Phase 1 (Price Reaction + VWAP + Tier Classification + Checklist)
- These 4 features will have the biggest impact on trade quality
- Then move to Phase 2 for additional filtering
- Phase 3 and 4 can be added over time as analytics improve
Expected Outcomes
- Higher Win Rate: Filtering out hedges/rolls and low-quality signals
- Better Entries: VWAP-based entry logic
- Better Exits: Flow-based exit signals
- Reduced Noise: Tier classification and checklist
- Institutional Detection: Strike clustering and delta weighting
Note: All suggestions are additive - they don't change existing code, just extend it with new services and enrichments.