Ctrl K
ComunidadGuías…

config.example.yaml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Copy to config.yaml and adjust. Behavior/config only — NO secrets (those live in .env).

# paper | live   (live also requires i_understand_live_trading: true)
mode: paper
i_understand_live_trading: false

# Which execution broker to use: paper | robinhood_mcp | robinstocks | alpaca
broker: robinhood_mcp    # this edition trades via Robinhood
# If the chosen broker can't trade options, fall back to this one (or null to stay read-only).
broker_fallback: paper

# Market data provider: robinhood | alpaca | paper  (see README > Optional integrations)
market_data: robinhood     # default: pull all data from the SAME Robinhood login (no Alpaca needed)

# Simulated buying power the paper broker reports — set to your REAL account size so the
# paper soak sizes positions realistically (default 100000 is a large sandbox balance).
paper_buying_power: 100000
# Seed fake demo positions into the paper broker. Leave true for local dev; set FALSE on a real
# paper soak — the demo fixtures otherwise inject phantom collateral that blocks entry sizing
# and show up as fake positions/P&L on the dashboard.
paper_seed_positions: true

# Loop cadences (seconds)
poll_interval_seconds: 60          # monitor loop during market hours
poll_interval_closed_seconds: 300  # monitor loop when market closed
reconcile_interval_seconds: 300
approval_timeout_seconds: 900      # how long an approval request stays valid
max_quote_age_seconds: 10          # reject quotes older than this when executing
auto_trip_after_errors: 0          # auto-engage kill switch after N consecutive errors (0=off)

execution:
  limit_buffer_pct: 0.02     # buy-to-close limit = mid * (1 + buffer)
  slippage_cap_pct: 0.05     # never pay more than ask * (1 + cap)
  fill_timeout_seconds: 60
  reprice_after_seconds: 20

robinhood:
  # Brokerage account that automated closes route through. MUST be agentic_allowed=true
  # and option_level_2+ (check via the get_accounts MCP tool). Required for live RH MCP
  # trading — leave blank and the RH broker stays read-only and falls back.
  account_number: ""         # your Agentic account number

# CSP auto-entry scanner (the "opening" side). OFF by default. Auto-enters sell-to-open
# cash-secured puts when a watchlist contract meets criteria — behind the same live-arming
# gate + kill switch as closes, plus the sizing caps and a real-time-feed requirement below.
entry:
  enabled: false             # master switch; scanner does not run unless true
  watchlist: []              # tickers to scan, e.g. ["MSFT","NVDA","AMD"]
  feed: indicative           # ONLY used when market_data=alpaca (set 'opra' then). Ignored for robinhood.
  scan_interval_seconds: 300
  earnings_gate: true        # skip a name whose earnings fall within (dte_max + exclude_earnings_days)
                             # days — never hold a short put through earnings. Enforced only when an
                             # earnings source is live (RH MCP + ROBINHOOD_MCP_TOKEN); else no-op.
  criteria:                  # CSP (cash-secured put) screening
    delta_min: 0.10          # short-put |delta| band. Measured on real option prints (docs/backtests.md):
    delta_max: 0.20          # 0.10-0.20 beat 0.18-0.28 under both fair and worst fills; assignments 12% vs 19%.
    dte_min: 7               # weeklies (7-14 DTE) for weekly income
    dte_max: 14
    min_annualized_yield: 0.20   # (premium/strike)/dte*365 floor (0.20 = 20%)
    min_open_interest: 100
    min_volume: 10
    max_spread_pct: 0.10     # bid-ask spread as fraction of mid
    exclude_earnings_days: 7  # (not yet enforced — needs an earnings calendar feed)
    # Variance-risk-premium gate: only sell a put whose IV is at least this multiple of the name's
    # 20-day realized vol. Pre-registered backtest on real prints: +1.90%/trade vs +1.20% ungated,
    # assignments 13% -> 10%, ~1/3 fewer entries; the trades it removes are the loss tail. Set null to disable.
    min_iv_rv_ratio: 1.3
  cc_criteria:               # covered-call screening (strike floor = cost basis, applied at runtime)
    delta_min: 0.20
    delta_max: 0.30
    dte_min: 7
    dte_max: 14
    min_annualized_yield: 0.20
    min_open_interest: 100
    min_volume: 10
    max_spread_pct: 0.10
    exclude_earnings_days: 7
    # Assignment clock (opt-in). Normally calls are never sold below cost basis. Set a number of
    # days and shares that are still under water that long after assignment may be written
    # against BELOW basis, inside cc_otm_band above spot, so the capital turns over instead of
    # sitting (measured on volatile names: ~35 days per cycle vs ~100 with the basis floor).
    # Works per ticker too (per_ticker: {SMR: {cc_below_basis_after_days: 42}}).
    cc_below_basis_after_days: null
    cc_otm_band: [0.05, 0.10]
  sizing:
    max_position_size_pct: 0.10        # cap each CSP at 10% of account value
    max_concurrent_positions: 5        # max open CSPs
    max_concurrent_cc: 10              # max open covered calls (covered, lower risk)
    total_bp_utilization_target: 0.50  # never commit more than 50% of buying power total
    buying_power_reserve_pct: 0.10     # always keep 10% of buying power unused
  # Per-ticker criteria overrides — merged over criteria/cc_criteria. Tune names you know well:
  per_ticker: {}             # e.g. {"NVDA": {"delta_max": 0.22}, "KO": {"dte_max": 21}}
  # Capital-aware tiers (optional). Names you'd like to trade once the account can afford ONE
  # contract under the per-name cap (max_pct_per_underlying, else max_position_size_pct).
  # min_collateral = strike * 100 snapshot; live prices refresh it daily. The bot only PROPOSES:
  # the Tuning tab lists them under "Ready to add" and a tap adds the name with its overrides.
  watchlist_tiers: {}        # e.g. {"KO": {min_collateral: 7000, per_ticker: {min_annualized_yield: 0.20}}}

# --- Market-regime read (systemic vs idiosyncratic) ---
macro:
  enabled: true
  symbols: ["SPY", "QQQ"]     # index-ETF proxies (VIX-proper isn't reachable via Alpaca yet)
  risk_off_vol: 0.30          # SPY 20d realized vol >= this -> risk_off (VIX~30 proxy)
  risk_off_drawdown: 0.10     # SPY 20d drawdown >= 10% -> risk_off
  systemic_drawdown: 0.05     # market 20d dd >= 5% -> a stock's drop reads "systemic"
  hard_gate: false            # true = pause ALL new entries while risk_off (default off: flags only)
  lookback_days: 330          # calendar days of index bars (>= 300 so the 200-day average exists)
  skip_confirmed_downtrend: false   # opt-in: pause NEW puts once SPY has closed below its 200-day
  downtrend_confirm_days: 5         # ...for this many straight sessions (flags only when off)

# --- AI trade-analyst (advisory) ---
# Reviews each screened + sized CSP candidate before submission and records a structured verdict.
# It can only flag/skip, NEVER widen risk. Needs ANTHROPIC_API_KEY (.env) + the `ai` extra.
ai:
  enabled: false             # turn on once ANTHROPIC_API_KEY is set
  model: claude-opus-4-8
  mode: advisory             # advisory = annotate only; veto = skip the trade on a "skip" verdict
  max_candidates_per_scan: 3 # cap Claude calls per scan (cost control)
  effort: medium             # low | medium | high | xhigh | max

# --- Roll defense (tested short puts) ---
# When a put is tested near expiry, roll it OUT (and down a strike) for a NET CREDIT instead of
# realizing a loss or accepting a bad-basis assignment. Only rolls for a credit; else it leaves the
# position to ride to assignment. Off by default.
roll:
  enabled: false
  roll_dte: 3              # only consider rolling within this many days of expiry
  roll_delta: 0.45         # ...and only when the put is tested (|delta| >= this)
  target_dte_min: 7        # roll out to a new expiry in this window
  target_dte_max: 14
  min_net_credit: 0.0      # require net credit >= this (0 = never pay to roll)
  max_target_delta: 0.35   # don't roll into an even more-tested put

# --- Gains sweep / tax reserve ---
# Each week, a share of NET realized gains (losses carry forward) is moved into a symbol of your
# choice by a small market order inside regular hours: SGOV (T-bills) to set aside taxes, or an
# index fund to reinvest premium. The holding is walled off from trading capital, never written
# against, never sold by the bot. One ledger row per week; run with dry_run: true for a cycle first.
tax_reserve:
  enabled: false
  pct: 0.20                  # share of the week's net realized gains
  symbol: SGOV               # any Robinhood-tradable stock or ETF
  weekday: 4                 # 0=Mon .. 4=Fri
  hour: 15                   # ET, inside regular hours (share market orders only fill then)
  minute: 40
  min_order_dollars: 5       # smaller amounts roll into the next week
  dry_run: true              # log + ledger the intended order, place nothing

# --- Scheduled push reports (hands-off heartbeat) ---
# For when you can't watch during the day: a daily digest (so 'no news' means 'all fine', not
# 'it died') + a weekly performance rollup. Delivered via notify.provider (Pushover). Times ET.
reporting:
  enabled: true
  daily_digest_hour: 16      # 24h ET; 16:15 = just after the close
  daily_digest_minute: 15
  weekly_report_weekday: 4   # 0=Mon .. 6=Sun; 4 = Friday

notify:
  provider: pushover         # none | ntfy | pushover  (set PUSHOVER_TOKEN/PUSHOVER_USER in .env)
  ntfy_topic: ""

tunnel:
  provider: none             # none | cloudflared | ngrok
  hostname: ""               # public host for one-tap approval links (e.g. agentic.example.com)

web:
  enabled: true             # run the FastAPI control/webhook API
  host: 0.0.0.0
  port: 8000
  signal_ttl_seconds: 600   # how long a queued TradingView signal stays actionable

# Rules evaluated per position each cycle. requires_approval is the hybrid-autonomy flag:
#   false -> auto-execute (use only for safe, deterministic rules)
#   true  -> push a notification and wait for one-tap approval
# Loss circuit breaker: freezes NEW entries when realized losses pile up (never force-closes;
# the monitor keeps managing open positions). Keys on realized P&L, not unrealized marks.
risk:
  loss_breaker_enabled: true
  lookback_days: 7
  max_realized_loss_pct: 0.10   # halt new entries if 7d realized P&L <= -10% of account (0 = off)
  max_consecutive_losses: 4     # halt new entries after 4 straight realized losers (0 = off)

rules:
  - name: profit-target
    rule_type: PROFIT_TARGET
    enabled: true
    requires_approval: false
    params:
      profit_pct: 0.5        # fixed: close once 50% of the credit is captured
      # Trailing mode: let winners run past the arm level, then close on a pullback from the peak.
      # trailing: true       # arm at profit_pct, then exit when profit falls trail_gap from its peak
      # trail_gap: 0.20      # give-back from the high-water mark (0.20 = 20 points of captured %)
  - name: stop-loss         # cap losers / avoid deep assignment (either trigger, whichever first)
    rule_type: STOP_LOSS
    enabled: true
    requires_approval: false
    params:
      loss_mult: 2.0         # close when cost-to-close >= 2x credit (~ -100% of credit)
      delta_stop: 0.5        # close when |delta| >= 0.50 (strike being breached)
  - name: dte-close
    rule_type: DTE
    enabled: true
    requires_approval: false
    params:
      dte_threshold: 2         # weeklies: close/let-expire near expiry (was 21 for monthlies)
      action: close            # alert | close
  - name: tv-signal
    rule_type: SIGNAL
    enabled: true
    requires_approval: true
    params:
      match: underlying      # underlying | occ