investing-algorithm-framework

repository·main·Indexed 23 days ago

https://github.com/coding-kitties/investing-algorithm-framework

A quantitative trading framework for creating trading bots, supporting the full workflow from strategy development to deployment. It features high-speed vector and realistic event-driven backtesting, a declarative Pipeline API for cross-sectional screens and signals using Polars DataFrames, and a tiered storage layer for efficient backtest bundle indexing and ranking via SQLite.

Tokens
161.9K
Snippets
335
Records
566
Agent score
80%

What's inside investing-algorithm-framework

  1. Overview of the Investing Algorithm Framework

    main

    The Investing Algorithm Framework is a comprehensive quantitative workflow tool designed to support the entire lifecycle of an investing strategy. It enables developers to:

    • Build strategies: Define quantitative logic for trading.
    • Vector Backtesting: Test thousands of strategies simultaneously using high-speed vector operations.
    • Event-Driven Backtesting: Perform realistic, bar-by-bar simulations to mimic live market conditions.
    • Compare results: Use a single dashboard to evaluate performance across different strategies.
    • Deploy: Move winning strategies into production.
  2. Overview of the Investing Algorithm Framework

    main

    The Investing Algorithm Framework is a Python-based library for building, testing, and deploying algorithmic trading systems. It supports the full lifecycle of strategy development, including data management, order execution, and performance analysis.

    Core capabilities include:

    • Strategy Development: Tools for implementing trading logic.
    • Backtesting: Dual approaches using Vector Backtesting (for fast signal analysis) and Event-Driven Backtesting (for realistic execution simulation).
    • Data Management: Integration with various data sources and the ability to load external CSV, JSON, or Parquet files from URLs with caching.
    • Performance Analysis: Over 30 metrics (CAGR, Sharpe, Sortino, etc.) and interactive reporting.
    • Deployment: Production-ready deployment to local environments or cloud providers like AWS Lambda and Azure Functions.
  3. What is a Trade and how does its lifecycle work?

    main

    A Trade represents a round-trip position, tracking the full lifecycle from entry to exit. It is distinct from an Order (an instruction to buy/sell) and a Position (current holdings).

    Trade Lifecycle

    1. Created: A buy order is placed; the trade record is created with status CREATED.
    2. Open: The buy order fills; the trade becomes OPEN. It now has an open_price, amount, and cost.
    3. Closed: A sell order fills against the trade, closing it. The net_gain is calculated, closed_at is set, and status becomes CLOSED.

    Note: A single sell order can close multiple trades, and a single trade can be closed by multiple partial sell orders.

  4. What is Vector Backtesting and when to use it

    main

    Vector backtesting is a high-performance approach that processes market data in a vectorized manner. It is designed for speed and scalability, typically running 10-100x faster than event-driven backtesting.

    Use Cases

    • Testing multiple strategy parameter combinations (parameter sweeps).
    • Running backtests across multiple time periods.
    • Working with large strategy sets (100+ strategies).
    • Needing rapid results to screen potential candidates.

    Critical Limitations

    Vector backtesting does NOT model order types or execution realism. It evaluates strategy signals (generate_buy_signals, generate_sell_signals) against price series but ignores:

    • OrderType.MARKET slippage and next-bar fill behavior.
    • OrderType.LIMIT resting fill logic.
    • OrderType.STOP and OrderType.STOP_LIMIT trigger logic.
    • Take-profit / stop-loss rules attached to trades.
    • Blotter slippage, commissions, or volume-based fill models.

    Recommended Workflow: Use vector backtests to quickly screen parameter combinations, then promote the best-performing strategies to event-driven backtests for realistic execution simulation.

  5. How Vector Backtest Pipelines work

    main

    When using BacktestService, pipelines are routed through the VectorPipelineEngine. This engine evaluates declared Factor objects across the entire backtest window once per strategy iteration using vectorized Polars operations.

    Execution Workflow:

    1. Panel Construction: The engine builds a long-form Polars panel (datetime, symbol, open, high, low, close, volume) truncated at the current bar to prevent look-ahead bias.
    2. Vectorized Evaluation: Each Factor is evaluated once per symbol over the full window using Polars.
    3. Sub-expression Caching: A ContextVar cache memoizes shared sub-expressions (e.g., if multiple factors use r.zscore() - r.demean(), r is only computed once).
    4. Universe Filtering: An optional universe mask filters the results, and the universe column is dropped from the final output.
    5. Data Access: The strategy accesses the resulting wide frame via data["YourPipelineClassName"].

    The strategy authoring surface is identical to the event-driven mode; you write the same Pipeline subclasses.

  6. Understand the Risk Parity (inverse-volatility weighting) strategy

    main

    The Risk Parity strategy aims to allocate capital across a basket of assets so that each asset contributes an equal amount of risk to the total portfolio.

    In this implementation, the strategy uses inverse-volatility weighting as a first-order approximation of true risk parity. The weighting logic follows the principle: weight ∝ 1/σ (where σ is volatility), followed by renormalization.

    Key characteristics within the framework:

    • Pattern: Uses a Periodic-rebalance pattern.
    • Logic: Portfolio targets are calculated as pure functions of the OHLCV (Open, High, Low, Close, Volume) history.
    • Execution: The strategy reads target weights, calculates the delta between target weights and current positions, and emits the required orders.
    • Cadence: Rebalancing is configured using time_unit=DAY combined with a monthly gate to ensure monthly rebalancing.
  7. How the TradeOrderEvaluator system works

    main

    The framework uses a TradeOrderEvaluator system to manage the lifecycle of orders and trades. This system is responsible for determining when orders are executed and how trade data is updated. The implementation of this evaluator changes fundamentally based on your environment:

    1. Live Trading: Uses LiveTradeOrderEvaluator to interact with real exchanges via CCXT, checking actual order statuses and updating trade prices based on real-time market data.
    2. Backtesting: Uses BacktestTradeOrderEvaluator to simulate execution using historical OHLCV data (Polars DataFrames), applying realistic rules for market and limit orders.

    Understanding this distinction is critical for ensuring your strategy behaves predictably when moving from simulation to production.

  8. Understand strategy compatibility via the Fit Legend

    main

    The framework uses a 'Fit Legend' to indicate how well the current architecture supports specific trading patterns:

    SymbolMeaning
    Sweet spot — Framework is well-suited and the example is end-to-end runnable.
    🟢Workable — Implementable with some additional bookkeeping in user code.
    🟡Partial — The pattern is shown, but a key primitive is approximated.
    🔴Not currently possible — The subfolder contains only a README.md explaining why.
  9. Retrieve aggregate metrics using BacktestSummaryMetrics

    main

    When performing multi-window backtests (such as walk-forward or permutation tests), you can retrieve a single roll-up of performance across all windows using BacktestSummaryMetrics. This is accessed via backtest.get_backtest_summary().

    For single-window backtests, these aggregate values collapse to the per-run values. For multi-window backtests, these metrics aggregate performance and provide robustness measures to evaluate how the strategy performs across different time periods.

    backtest.get_backtest_summary()
  10. Fixed vs Trailing Take Profit modes

    main

    Fixed (trailing=False)

    Reference price is the entry price. The rule fires the first time the price touches entry × (1 + threshold/100). This is best for immediate profit taking.

    Example: Buy at 100, threshold=5% $\rightarrow$ exit price = 105. When price hits 105, exit.

    Trailing (trailing=True)

    The take-profit price is not set at entry. It is armed only when the percentage_threshold is first reached. Once armed, the exit price ratchets with the rolling peak, allowing winners to run while locking in profit on pullbacks.

    Example:

    1. Buy at 100, threshold=5%.
    2. Price hits 105 $\rightarrow$ Rule arms, take_profit_price = 105 (peak=105).
    3. Price rises to 120 $\rightarrow$ take_profit_price = 114 (peak=120).
    4. Price rises to 150 $\rightarrow$ take_profit_price = 142.50 (peak=150).
    5. Price falls to 142.50 $\rightarrow$ Exit at ~142.50.