Logic · sync_guard

Read-only view of active client JSON

{
    "schema_version": "1.0.0",
    "name": "market_data_news_sync_guard",
    "description": "Timestamp-aware synchronization layer for delayed news, Tradier sandbox quotes, option quotes, candles, VWAP and TA-Lib trade monitoring. Prevents false VWAP rejects and blocks auto-entry when data is stale or unsynced.",
    "environment": {
        "mode": "sandbox",
        "timezone": "America\/New_York",
        "market_session": {
            "premarket_start": "04:00:00",
            "regular_start": "09:30:00",
            "regular_end": "16:00:00",
            "after_hours_end": "20:00:00"
        }
    },
    "data_sources": {
        "news": {
            "providers": [
                "benzinga",
                "white_house_feed",
                "truth_social_or_president_social",
                "reuters_optional",
                "manual_api"
            ],
            "required_fields": [
                "event_id",
                "headline",
                "source",
                "actual_news_ts",
                "received_ts",
                "symbols",
                "sector_tags",
                "direction_hint",
                "source_url"
            ],
            "timestamp_priority": [
                "actual_news_ts",
                "provider_published_ts",
                "received_ts"
            ],
            "max_expected_delay_seconds": 300,
            "if_delay_unknown": "mark_delay_unknown_and_sync_before_decision"
        },
        "equity_quotes": {
            "provider": "tradier_sandbox",
            "required_fields": [
                "symbol",
                "bid",
                "ask",
                "last",
                "volume",
                "quote_ts"
            ],
            "poll_interval_seconds": 1,
            "max_expected_delay_seconds": 300
        },
        "option_quotes": {
            "provider": "tradier_sandbox",
            "required_fields": [
                "contract_symbol",
                "bid",
                "ask",
                "last",
                "open_interest",
                "volume",
                "quote_ts"
            ],
            "poll_interval_seconds": 1,
            "max_expected_delay_seconds": 300
        },
        "candles": {
            "provider": "market_data_provider_or_polygon",
            "timeframes": [
                "1m",
                "5m"
            ],
            "required_fields": [
                "symbol",
                "open",
                "high",
                "low",
                "close",
                "volume",
                "candle_start_ts",
                "candle_end_ts",
                "is_closed"
            ],
            "use_only_closed_candles_for_vwap": true,
            "minimum_closed_candles_required": {
                "premarket": 3,
                "regular": 2
            }
        }
    },
    "sync_policy": {
        "live": {
            "max_cross_source_skew_seconds": 90,
            "reject_if_stale_after_seconds": 180,
            "vwap_hard_reject_enabled": true,
            "use_pending_price_sync": true
        },
        "sandbox": {
            "max_cross_source_skew_seconds": 420,
            "reject_if_stale_after_seconds": 600,
            "vwap_hard_reject_enabled": false,
            "use_pending_price_sync": true,
            "delay_adjust_news_to_market_data": true,
            "allow_recheck_until_seconds": 600
        },
        "timestamp_fields_to_compare": [
            "signal.received_ts",
            "signal.actual_news_ts",
            "equity_quote.quote_ts",
            "option_quote.quote_ts",
            "last_closed_candle.candle_end_ts",
            "server_now_ts"
        ],
        "clock_drift": {
            "max_server_clock_drift_seconds": 5,
            "on_clock_drift_exceeded": "pause_auto_trading_and_alert"
        }
    },
    "status_lifecycle": {
        "new_signal": "pending_sync_check",
        "data_not_aligned": "pending_price_sync",
        "data_aligned_waiting_vwap": "pending_vwap_confirmation",
        "vwap_passed": "approved_pending_risk_checks",
        "risk_passed": "approved_pending_order",
        "entered": "open_monitoring",
        "closed": "closed",
        "failed_statuses": [
            "reject_stale_data",
            "reject_vwap_confirmed",
            "reject_wide_spread",
            "reject_duplicate_position",
            "reject_direction_mismatch",
            "reject_monitor_not_active",
            "reject_no_closed_candles",
            "reject_api_error"
        ]
    },
    "sync_decision_rules": [
        {
            "rule_id": "SYNC_001",
            "name": "Require timestamp alignment before VWAP rejection",
            "logic": "If news, equity quote, option quote, and last closed candle timestamps are not aligned inside max_cross_source_skew_seconds, set status=pending_price_sync. Do not reject_vwap yet."
        },
        {
            "rule_id": "SYNC_002",
            "name": "Reject stale data only after tolerance expires",
            "logic": "If any required timestamp is older than reject_if_stale_after_seconds after sync retries, set status=reject_stale_data."
        },
        {
            "rule_id": "SYNC_003",
            "name": "Use last completed candle only",
            "logic": "VWAP and TA-Lib checks must use the most recent candle where is_closed=true. Never use a partially forming 1m candle for hard decisions."
        },
        {
            "rule_id": "SYNC_004",
            "name": "Sandbox delay mode",
            "logic": "In sandbox, delay tolerance is wider and vwap_hard_reject_enabled=false. VWAP failure becomes pending_vwap_confirmation first, then reject_vwap_confirmed only after synchronized recheck."
        }
    ],
    "vwap_rules": {
        "fast_news": {
            "vwap_required_before_entry": false,
            "vwap_confirmation_window_seconds": 180,
            "reject_only_after_confirmation_window": true,
            "must_be_time_synced_before_reject": true,
            "calls_pass_if": [
                "last_closed_candle.close >= vwap",
                "or price_reclaimed_vwap_and_held_for_1_closed_candle"
            ],
            "puts_pass_if": [
                "last_closed_candle.close <= vwap",
                "or price_rejected_vwap_and_held_below_for_1_closed_candle"
            ],
            "on_fail_before_window_expires": "pending_vwap_confirmation",
            "on_fail_after_window_expires": "reject_vwap_confirmed"
        },
        "a_plus": {
            "vwap_required_before_entry": true,
            "must_be_time_synced_before_reject": true,
            "calls_pass_if": [
                "last_closed_candle.close >= vwap"
            ],
            "puts_pass_if": [
                "last_closed_candle.close <= vwap"
            ],
            "on_fail": "reject_vwap_confirmed"
        },
        "premarket": {
            "use_premarket_vwap": true,
            "regular_session_reset_at": "09:30:00",
            "after_open_wait_closed_candles": 2,
            "do_not_compare_premarket_news_to_regular_vwap_until_reset_complete": true
        }
    },
    "order_entry_guards": {
        "require_sync_passed": true,
        "require_stop_monitor_active_before_order": true,
        "require_duplicate_lock_before_order": true,
        "require_direction_validation": true,
        "max_option_spread_pct": {
            "default": 10,
            "fast_news_extreme": 15,
            "sandbox_testing_allow_record_only": 50
        },
        "minimum_option_volume": {
            "default": 100,
            "large_cap_liquid_exception": 25
        },
        "minimum_open_interest": {
            "default": 250,
            "large_cap_liquid_exception": 50
        },
        "reject_if_option_bid_zero": true
    },
    "duplicate_position_lock": {
        "enabled": true,
        "scope": [
            "trading_day",
            "session",
            "strategy",
            "ticker",
            "contract_symbol",
            "direction",
            "event_cluster_id"
        ],
        "fast_news_pyramiding_allowed": false,
        "reject_reason": "reject_duplicate_position",
        "lock_ttl_seconds": 23400
    },
    "direction_classifier_rules": {
        "oil_energy": {
            "bullish_energy_calls": [
                "oil higher",
                "crude spikes",
                "supply disruption",
                "Hormuz closure",
                "attack on oil infrastructure",
                "Middle East escalation",
                "sanctions tighten"
            ],
            "bearish_energy_puts": [
                "oil lower",
                "ceasefire",
                "de-escalation",
                "peace talks progress",
                "Hormuz reopening",
                "supply restored",
                "deal reached"
            ],
            "on_conflict": "manual_review"
        },
        "semiconductors": {
            "bullish_calls": [
                "AI demand upside",
                "raised guidance",
                "major partnership",
                "chip export approval",
                "earnings beat with strong guidance"
            ],
            "bearish_puts": [
                "guidance cut",
                "export restriction",
                "bad reaction to good earnings",
                "sector de-risking",
                "competitive pressure"
            ],
            "on_conflict": "manual_review"
        }
    },
    "premarket_direction_validation": {
        "enabled": true,
        "required": true,
        "max_put_score_when_conflicts": 79,
        "max_put_score_fade_watch": 72,
        "min_premarket_change_pct_for_rebound": 0.25,
        "min_top_mover_inject_pct": 3,
        "fade_watch_only_tickers": [
            "NVDA",
            "AVGO",
            "BTC",
            "MSTR"
        ],
        "block_put_confirm_on_rebound_tickers": [
            "NVDA",
            "AMD",
            "AVGO",
            "INTC",
            "MU",
            "MRVL",
            "SMCI",
            "SMH"
        ],
        "oil_fade_put_tickers": [
            "XLE",
            "USO"
        ],
        "call_flip_allowed_tickers": [
            "MRVL",
            "SMCI",
            "AAPL",
            "MU",
            "AMD",
            "INTC",
            "AVGO"
        ],
        "ticker_alias_map": {
            "BTC": "MSTR",
            "BITCOIN": "MSTR"
        },
        "top_mover_catalyst_phrases": [
            "s&p 500",
            "s&p500",
            "inclusion",
            "index addition",
            "joins s&p",
            "added to the s&p"
        ],
        "priority_inject_tickers": [
            "SMCI",
            "MRVL",
            "MU",
            "AMD",
            "INTC",
            "AVGO"
        ],
        "smci_catalyst_phrases": [
            "unusual options",
            "heavy call",
            "call volume",
            "options activity",
            "premarket gainer",
            "shares up",
            "surges",
            "jumps"
        ],
        "energy_inject_tickers": [
            "XLE",
            "USO"
        ],
        "energy_catalyst_phrases": [
            "crude oil",
            "oil prices",
            "wti",
            "brent",
            "hormuz",
            "iran",
            "israel",
            "middle east",
            "geopolitical",
            "energy sector",
            "oil spike",
            "oil rally"
        ],
        "do_not_score_put_above_80_when": [
            "ticker_premarket_change_positive",
            "sector_etf_positive",
            "index_futures_positive",
            "fresh_news_polarity_bullish"
        ],
        "convert_to_fade_watch_when": [
            "prior_day_selloff_but_current_premarket_rebound",
            "gap_up_after_panic_selling",
            "put_score_based_only_on_old_news"
        ],
        "put_confirmation_required": [
            "price_below_vwap",
            "first_closed_candle_rejects_vwap_or_premarket_high",
            "sector_etf_below_vwap",
            "options_put_flow_after_open",
            "bid_ask_spread_acceptable"
        ],
        "sector_etf_map": {
            "semiconductor": [
                "SMH",
                "SOXX"
            ],
            "energy": [
                "XLE",
                "USO"
            ],
            "crypto": [
                "COIN",
                "MSTR"
            ],
            "tech_broad": [
                "QQQ",
                "XLK"
            ],
            "index": [
                "SPY",
                "QQQ"
            ]
        },
        "ticker_sector_map": {
            "NVDA": "semiconductor",
            "AMD": "semiconductor",
            "AVGO": "semiconductor",
            "MRVL": "semiconductor",
            "MU": "semiconductor",
            "SMCI": "semiconductor",
            "ARM": "semiconductor",
            "INTC": "semiconductor",
            "IBM": "semiconductor",
            "XLE": "energy",
            "USO": "energy",
            "XOM": "energy",
            "CVX": "energy",
            "COIN": "crypto",
            "MSTR": "crypto",
            "BTC": "crypto",
            "IBIT": "crypto",
            "AAPL": "tech_broad",
            "MSFT": "tech_broad",
            "NOW": "tech_broad"
        },
        "index_futures_symbols": [
            "QQQ",
            "SPY"
        ],
        "rebound_headline_phrases": [
            "rebound",
            "recovery",
            "bounce",
            "rally",
            "gap up",
            "premarket higher",
            "shares up",
            "joins s&p",
            "inclusion"
        ],
        "stale_selloff_phrases": [
            "friday selloff",
            "prior selloff",
            "last week weakness",
            "earnings miss",
            "guidance cut",
            "sector de-risking"
        ]
    },
    "ta_lib_monitoring": {
        "enabled": true,
        "start_before_entry_required": true,
        "indicators": {
            "vwap": {
                "source": "closed_1m_candles"
            },
            "ema_9": {
                "timeframe": "1m"
            },
            "ema_20": {
                "timeframe": "1m"
            },
            "rsi_14": {
                "timeframe": "1m"
            },
            "atr_14": {
                "timeframe": "1m"
            },
            "macd": {
                "timeframe": "1m"
            }
        },
        "monitor_interval_seconds": 1,
        "heartbeat_required": true,
        "heartbeat_timeout_seconds": 5,
        "on_monitor_failure": "block_new_entries_and_alert"
    },
    "exit_rules": {
        "hard_stop_loss_pct": -20,
        "emergency_stop_loss_pct": -30,
        "profit_protection": {
            "enabled": true,
            "activate_at_profit_pct": 25,
            "trail_from_high_pct": 15
        },
        "spread_exit_guard": {
            "if_spread_pct_above": 25,
            "use_limit_near_bid_for_exit": true,
            "max_exit_retry_seconds": 30,
            "after_retry_use_marketable_limit": true
        },
        "stale_quote_exit_guard": {
            "max_quote_age_seconds_live": 10,
            "max_quote_age_seconds_sandbox": 420,
            "on_stale_quote": "pause_exit_once_and_retry_quote",
            "max_retries": 3
        },
        "sell_to_close_required_on_stop": true
    },
    "sync_algorithm_pseudocode": {
        "data_is_time_aligned": [
            "collect actual_news_ts, received_ts, equity_quote_ts, option_quote_ts, last_closed_candle_end_ts",
            "remove nullable actual_news_ts only if provider did not provide it",
            "newest=max(timestamps)",
            "oldest=min(timestamps)",
            "skew_seconds=newest-oldest",
            "return skew_seconds <= config.sync_policy[mode].max_cross_source_skew_seconds"
        ],
        "vwap_gate": [
            "if not data_is_time_aligned: status=pending_price_sync",
            "else if no last closed candles: status=reject_no_closed_candles",
            "else if strategy=fast_news and vwap fails before confirmation window: status=pending_vwap_confirmation",
            "else if vwap fails after confirmation window: status=reject_vwap_confirmed",
            "else status=approved_pending_risk_checks"
        ],
        "entry_gate": [
            "confirm sync passed",
            "confirm duplicate lock acquired",
            "confirm option spread acceptable",
            "confirm direction matches catalyst",
            "confirm TA-Lib monitor heartbeat active",
            "place order only after all checks pass"
        ]
    },
    "logging": {
        "log_every_signal": true,
        "log_path": "logs\/sync_guard\/",
        "fields": [
            "event_id",
            "event_cluster_id",
            "strategy",
            "ticker",
            "direction",
            "contract_symbol",
            "actual_news_ts",
            "received_ts",
            "equity_quote_ts",
            "option_quote_ts",
            "last_closed_candle_end_ts",
            "server_now_ts",
            "cross_source_skew_seconds",
            "data_delay_seconds",
            "vwap",
            "last_closed_price",
            "vwap_result",
            "status_before",
            "status_after",
            "reject_reason",
            "option_bid",
            "option_ask",
            "option_mid",
            "spread_pct",
            "monitor_heartbeat_ts",
            "order_id",
            "position_id"
        ],
        "dashboard_alerts": [
            "pending_price_sync_over_120_seconds",
            "reject_stale_data",
            "reject_vwap_confirmed",
            "duplicate_position_attempt",
            "stop_monitor_not_active",
            "hard_stop_triggered",
            "tradier_sell_to_close_failed"
        ]
    },
    "test_cases": [
        {
            "name": "Delayed news plus delayed sandbox quotes should not reject VWAP immediately",
            "input": {
                "strategy": "fast_news",
                "mode": "sandbox",
                "news_delay_seconds": 300,
                "quote_delay_seconds": 300,
                "candle_delay_seconds": 240,
                "initial_vwap_fail": true
            },
            "expected_status": "pending_price_sync"
        },
        {
            "name": "Synced put below VWAP should pass",
            "input": {
                "direction": "put",
                "last_closed_price_relation_to_vwap": "below",
                "data_synced": true
            },
            "expected_status": "approved_pending_risk_checks"
        },
        {
            "name": "Synced put above VWAP after confirmation window should reject",
            "input": {
                "direction": "put",
                "last_closed_price_relation_to_vwap": "above",
                "data_synced": true,
                "confirmation_window_expired": true
            },
            "expected_status": "reject_vwap_confirmed"
        },
        {
            "name": "Duplicate same contract must reject before order",
            "input": {
                "existing_open_position": true,
                "same_contract_symbol": true
            },
            "expected_status": "reject_duplicate_position"
        },
        {
            "name": "Stop monitor inactive blocks entry",
            "input": {
                "ta_lib_monitor_heartbeat_active": false
            },
            "expected_status": "reject_monitor_not_active"
        }
    ],
    "deployment_safety": {
        "auto_trading_allowed_in_sandbox": false,
        "paper_trade_only_until_tests_pass": true,
        "minimum_required_passing_tests": [
            "sync_timestamp_alignment",
            "vwap_pending_not_false_reject",
            "duplicate_lock",
            "spread_filter",
            "stop_loss_sell_to_close",
            "monitor_heartbeat"
        ],
        "manual_override_allowed": true
    }
}