Skip to content

Latest commit

 

History

History
352 lines (268 loc) · 14.4 KB

File metadata and controls

352 lines (268 loc) · 14.4 KB

Example Bots

Real-world bot implementations demonstrating different patterns and strategies.

eurusdtreebot.py

Decision tree-based strategy for EUR/USD.

Pattern: Simple decisionFunction() with multiple thresholds

class EURUSDTreeBot(Bot):
    def decisionFunction(self, row):
        if row["trend_sma_slow"] <= self.sma_slow_threshold:
            if row["trend_macd_signal"] <= self.macd_signal_threshold:
                return -1
            # ... more conditions
        return 0

feargreedbot.py

Uses external Fear & Greed Index API.

Pattern: Override makeOneIteration() for external data

class FearGreedBot(Bot):
    def makeOneIteration(self):
        index = get_fear_greed_index()
        if index < 20:  # Extreme fear
            self.buy("QQQ")
        elif index > 80:  # Extreme greed
            self.sell("QQQ")
        return 0

sharpeportfoliooptweekly.py

Portfolio optimization with Sharpe ratio.

Pattern: Complex makeOneIteration() for multi-asset optimization

class SharpePortfolioOptWeekly(Bot):
    def makeOneIteration(self):
        # Fetch multiple symbols
        data = self.getYFDataMultiple(["QQQ", "GLD", "TLT"])
        
        # Optimize portfolio
        weights = optimize_sharpe_ratio(data)
        
        # Rebalance
        self.rebalancePortfolio(weights)
        return 0

xauzenbot.py

Gold (XAU) trading bot.

Pattern: Simple decisionFunction() with RSI and MACD

gptbasedstrategytabased.py

GPT-based strategy with technical analysis.

Pattern: Uses LLM for decision making with TA indicators

aihedgefundbot.py

AI-driven portfolio rebalancing.

Pattern: Reads decisions from external database and rebalances

deepseektoolbot.py

AI-driven portfolio research and rebalancing with tools. The main LLM uses tools (market data, news, earnings, insider trades, portfolio, recent trades) to research symbols and submits target weights via a custom submit_portfolio_weights tool. The cheap LLM then sanity-checks the submitted weights; if it rejects them, the bot retries once with the main LLM. Requires OPENROUTER_API_KEY.

Pattern: Override get_ai_tools() for custom tools; use main LLM for tool flow, cheap LLM for output validation and fallback

ta_regime_bot.py (TARegimeAdaptiveBot)

Single-asset bot that uses only historic OHLCV and TA (no Fear & Greed). It classifies regime as trend vs mean reversion via a Hurst-style proxy (lag-1 autocorrelation of returns), then applies ADX/MACD/EMA in trend regime and RSI/Bollinger BBP (and optional z-score) in mean-reversion regime. All decision logic lives in utils.ta_regime; the bot only fetches data and delegates.

Pattern: Minimal bot; reusable logic in utils.ta_regime; decisionFunction(row) calls ta_regime_decision(row, self.data, **self._ta_params).

For the mathematical and quant concepts (Hurst, R/S, variance ratio, z-score, Hilbert/Ehlers, entropy) and source links, see TA Regime Bot: Mathematical and Quant Concepts.

adaptivemeanreversionbot.py

Volatility-gated mean-reversion on QQQ.

Pattern: decisionFunction() with overridden getYFDataWithTA() to inject custom columns (200-day SMA, ATR rolling mean, prev-session high, BBW squeeze minimum). Fully backtestable.

class AdaptiveMeanReversionBot(Bot):
    param_grid = {
        "wr_threshold": [-80, -85, -90, -95],
        "atr_multiplier": [1.5, 2.0, 2.5, 3.0],
    }

    def decisionFunction(self, row):
        # SELL: snap-back above previous session's high
        if prev_high > 0 and close > prev_high:
            return -1
        # BUY: oversold (WR < -90), above 200 SMA, calm ATR, no squeeze
        if close > sma_200 and wr < self.wr_threshold and atr < multiplier * atr_ma:
            return 1
        return 0

Hyperparameters (param_grid):

Parameter Grid Effect
wr_threshold -80, -85, -90, -95 Depth of oversold required for entry
atr_multiplier 1.5, 2.0, 2.5, 3.0 How aggressive the volatility gate is

Run AdaptiveMeanReversionBot().local_optimize() to find the best combination on recent data.

goldenbutterflymombot.py

Golden Butterfly five-asset portfolio with Relative Rotation Graph (RRG) momentum overlay for weekly rebalancing.

Pattern: makeOneIteration() + rebalancePortfolio(). Multi-asset (Pattern B). Not backtestable.

class GoldenButterflyMomBot(Bot):
    # Universe: VTI, IJS, TLT, SHY, IAU — benchmark: SPY
    def makeOneIteration(self):
        # Compute RS-Ratio and RS-Momentum vs SPY (z-scored)
        # Classify: Leading / Weakening / Improving / Lagging
        # OBV rising → upgrade Improving to full weight
        # CMF < 0   → downgrade Leading to half weight
        # Lagging   → redirect to SHY (or USD if SHY is also Lagging)
        self.rebalancePortfolio(target, onlyOver50USD=True)

RRG Quadrant → Weight:

Quadrant Condition Weight
Leading + CMF ≥ 0 rs_ratio_z > 0 AND rs_mom_z > 0 20%
Leading + CMF < 0 distribution warning 10% → 10% to SHY
Improving + OBV↑ rs_ratio_z < 0 AND rs_mom_z > 0, volume confirm 20%
Improving, no OBV accumulation unconfirmed 10% → 10% to SHY
Weakening rs_ratio_z > 0 AND rs_mom_z < 0 10% → 10% to SHY
Lagging rs_ratio_z < 0 AND rs_mom_z < 0 0% → 20% to SHY

Research basis: Strategic Synthesis of Adaptive Mean Reversion and Multi-Asset Rotation — covers RRG mathematics, UIS scaling, volatility clustering theory, and the 2026 ETF landscape.

stocknewssentimentbot.py

AI-driven news sentiment trading across multiple symbols.

Pattern: makeOneIteration() — reads the stock_news DB table (populated nightly by calculate_portfolio_worth), classifies aggregate headline sentiment per symbol via AI, and executes trades on medium/high-confidence signals.

class StockNewsSentimentBot(Bot):
    def makeOneIteration(self):
        # Fetch unacted news rows from last 2 days
        # Mark acted_on=True BEFORE AI call (crash-safe deduplication)
        # AI returns {"direction": "BUY"|"SELL"|"HOLD", "confidence": "low"|"medium"|"high"}
        # Buy 20% of cash per BUY signal; sell all on SELL signal

Key details:

Setting Value
Lookback window 2 days of headlines
Max headlines per AI call 5 per symbol
Position size 20% of cash per BUY
Confidence filter medium or high only
Crash safety acted_on flag set before AI call

Schedule: 30 22 * * 1-5 — runs 30 min after calculate_portfolio_worth (which refreshes the news feed).

synthesizedhyperconvexitybot.py

Five-layer leveraged ETF strategy trading TQQQ / SQQQ / IEF.

Pattern: makeOneIteration() — multi-instrument, multi-data-source. Not backtestable with the built-in engine.

class SynthesizedHyperConvexityBot(Bot):
    def makeOneIteration(self):
        # Stage 2 (QQQ > rising 30-wk SMA) + squeeze + VIX declining → buy TQQQ
        # Stage 4 (QQQ < falling 30-wk SMA) + F&G not panicking → buy SQQQ
        # Stage 1 / 3 / unknown → rotate to IEF
        # Black Swan CB: TQQQ ≥-20% or QQQ ≥-7% → liquidate all → IEF

Signal stack:

Layer Indicator Role
Stage Analysis 30-week SMA slope on QQQ Macro regime (direction)
BB/KC Squeeze Bollinger Bands inside Keltner Channels Entry timing
VIX Trend VIX vs 20-day MA Gamma unwind confirmation
Sentiment Gate Fear & Greed (>75 / <25) Contrarian filter at extremes
Black Swan CB Daily TQQQ/QQQ drop thresholds Hard crash exit

Position sizing: Vol-of-Vol Kelly proxy — ATR/price ratio scales stake between 25% (high vol) and 80% (low vol) of available cash.

Research basis: Synthesized Hyper-Convexity Engine — covers leveraged ETF volatility drag, Weinstein Stage Analysis, BB/KC squeeze mechanics, gamma squeeze dynamics, and Vol-of-Vol Kelly sizing.

recursivedecayharvestbot.py (RecursiveDecayHarvestBot)

TQQQ regime-switching strategy with dual crash filter. Holds 3x Nasdaq-100 (TQQQ) during QQQ uptrends with calm volatility; exits to cash on UVXY RSI spike or QQQ SMA200 breakdown. Captures leveraged (3×) upside in bull markets while avoiding the beta-slippage decay spiral that destroys leveraged ETF holders in bear/volatile regimes.

Pattern: decisionFunction() with overridden getYFDataWithTA() to inject multi-symbol derived columns (QQQ SMA200 + close, UVXY RSI). Backtestable. getYFDataMultiple fetches raw OHLCV for QQQ and UVXY; RSI and SMA are computed in _enrich() and date-merged onto TQQQ rows.

class RecursiveDecayHarvestBot(Bot):
    param_grid = {
        "uvxy_rsi_exit": [55, 60, 65, 70],
        "sell_buffer": [0.02, 0.05, 0.08, 0.12],
    }

    def decisionFunction(self, row):
        # SELL: UVXY RSI spike — volatility panic, decay accelerates
        if uvxy_rsi > self.uvxy_rsi_exit:
            return -1
        # SELL: QQQ trend broken with sell_buffer gap
        if qqq_close < qqq_sma200 * (1 - self.sell_buffer):
            return -1
        # BUY: QQQ uptrend + calm UVXY → hold TQQQ
        if qqq_close > qqq_sma200 and uvxy_rsi <= self.uvxy_rsi_exit:
            return 1
        return 0

Instruments: TQQQ (primary), QQQ (trend filter), UVXY (crash filter)

Hyperparameters (param_grid):

Parameter Grid Effect
uvxy_rsi_exit 55, 60, 65, 70 UVXY RSI threshold: lower = exit sooner on fear spikes
sell_buffer 0.02, 0.05, 0.08, 0.12 QQQ SMA breakdown buffer: wider = fewer SMA exits

Run RecursiveDecayHarvestBot().local_optimize() to find the best combination on recent data.

Research basis: Recursive Adversarial Arbitrage — covers volatility decay theory, beta slippage mathematics, dark pool footprints, and multi-agent AI consensus frameworks for leveraged ETF strategies.

option_indexvolbot.py (OptionIndexVolBot)

Sells SPY iron condors when implied vol sits above a forecast of the vol SPY will actually deliver. It is the one option bot with backtested, uncorrelated alpha: +2.0%/yr, t 4.28, beta 0.01 (see Index Vol Backtest). Since 2026-09-28 it skips entries while the vol curve is inverted, which gives half the drawdown (round 3).

Pattern: an OptionStrategyBot. The bot only names its rules and calls one pure decision function. The function reads the market and the book and returns actions (Open, Close, Hedge), and the framework executes them. The same function runs in the replay backtest over stored chains (utils/option_replay.py) and on the synthetic chain (scripts/onetime_index_vol_backtest.py --decide). The backtests therefore test exactly what trades, which the built-in engine cannot do for options. See Options below.

class OptionIndexVolBot(OptionStrategyBot):
    RULES: ClassVar[IndexVolRules] = IndexVolRules(
        target_dte=35,
        put_delta=0.10,
        call_delta=0.10,
        width_pct=0.10,
        min_gap=0.03,
        exit_dte=7,
        max_term_ratio=1.0,  # no new condor while VIX > VIX3M
    )

    def __init__(self, **kwargs):
        super().__init__("option_IndexVolBot", symbol="SPY", interval="1d", period="5y", **kwargs)

    def decide(self, market: Market, holdings: Holdings) -> list[Action]:
        return decide_indexvol(market, holdings, self.RULES, "SPY")


# utils/option_strategies.py: pure, shared by the live bot and every backtest
def decide_indexvol(market, holdings, rules, underlying="SPY"):
    if underlying in holdings.underlyings():
        book = holdings.book(underlying)  # the same OptionBook live and in replay
        reason = index_vol_exit_reason(book.credit, book.pnl, book.dte, rules)
        return [Close(underlying, reason=reason)] if reason else []

    view = market.chain(underlying, rules.target_dte)
    if view is None or not view.live:
        return []  # never opens a structure off-hours
    fair = om.har_rv_forecast(...)  # HAR-RV forecast of realized vol to expiry
    iv = options.atm_iv(view)
    term = term_ratio(market.vol_index("^VIX"), market.vol_index("^VIX3M"))
    if not index_vol_entry_ok(iv, fair, market.vol_index("^VIX"), rules, term_ratio=term):
        return []  # only sells when IV >= fair vol + a gap and the curve is not inverted
    pick = options.select_iron_condor(
        underlying,
        rules.put_delta,
        rules.width_pct * view.spot,
        rules.target_dte,
        view=view,
        call_delta=rules.call_delta,
    )
    return [Open(pick, rules.max_risk_pct * holdings.equity())]  # sized by worst-case loss

Key details:

Setting Value
Structure 10-delta short put/call, wings 10% of spot further out
Entry gate ATM IV ≥ HAR fair vol + 3 points, ^VIX < 40, VIX/VIX3M ≤ 1.0
Exit 50% of credit, 2x credit stop, or 7 DTE left
Sizing worst-case loss ≤ 20% of the book (Open.max_risk_usd, capped by free cash)

The rules are pure functions in utils/option_rules.py (IndexVolRules, index_vol_entry_ok, index_vol_exit_reason). The decision that combines them is utils/option_strategies.decide_indexvol.

For many underlyings from one book, subclass OptionUniverseBot and set UNIVERSE, RULES and DECIDE. option_crossvolbot.py is about 20 lines.

Options

Ten more option bots trade AAPL and the S&P 100 with strike-by-delta selection, spreads, condors, the wheel, PMCC, collars, cross-sectional and earnings-driven strategies. Full list, strategy table and framework reference (selecting by delta, margin math, physical settlement, greeks, IV solving, the vol surface): AGENTS.md § Options. Backtests: option-bots-2026-09.md, option-bots-round2-2026-09.md, index-vol-2026-09.md, option-round3-2026-09.md.

Learning from Examples

Each example demonstrates:

  • Different implementation approaches
  • Common patterns and best practices
  • Real-world trading strategies
  • Error handling and edge cases

Next Steps