akquant Documentation

repository·main·Indexed 23 days ago

https://github.com/akfamily/akquant

A high-performance quantitative trading framework based on Rust and Python (version 0.3.27) designed for strategy development and backtesting. It features a high-efficiency Rust core with a flexible Python interface, supporting machine learning, TA-Lib technical indicators, and advanced order management including OCO and bracket orders. Capabilities include multi-symbol and multi-frequency backtesting, walk-forward optimization, real-time streaming monitoring, and interactive HTML reporting via Plotly.

Tokens
96.2K
Snippets
169
Records
356
Agent score
80%

What's inside akquant

  1. Browse the Quantitative Investment Textbook Structure

    main

    The AKQuant textbook follows a structured path from foundations to advanced topics like machine learning and high-performance factor mining. Note that while the skeleton is available in English, the full content is currently available in Chinese.

    Key learning paths include:

    • Foundations: Environment setup, programming survival, and data acquisition.
    • Core Engine: Event-driven backtesting principles and strategy development.
    • Market Specifics: A-Share market, Futures, and Options.
    • Advanced Quantitative Methods: Strategy evaluation, parameter optimization, machine learning, and factor mining.
    • Operations: Live trading systems and the AKQuant Indicator system.
  2. Core capabilities and feature examples

    main

    The examples/ directory contains specialized scripts for various quantitative trading tasks:

    Order Management & Execution

    • Complex Orders: 06_complex_orders.py demonstrates the place_bracket assistant and automatic OCO (One-Cancels-the-Other) linkage.
    • Trailing Orders: 36_trailing_orders.py shows Trailing Stop and StopLimit assistants.
    • Live Trading: 05_live_trading_ctp.py provides a CTP interface example, while 38_live_functional_strategy_demo.py shows the run_live functional entry point.
    • Broker Customization: 35_custom_broker_registry_demo.py covers custom Broker registration and factory creation.

    Strategy Development & Logic

    • Event Callbacks: 08_event_callbacks.py demonstrates unified callbacks including on_start, on_bar, on_order, on_trade, on_reject, on_timer, on_portfolio_update, and on_stop.
    • Machine Learning: 09_ml_framework.py covers ML basics, and 10_ml_walk_forward.py covers Walk-Forward training/evaluation.
    • Risk Management: 20_risk_management_demo.py for general risk, and 47_margin_liquidation_audit_demo.py for margin liquidation auditing in margin mode.
    • Indicators: 60_custom_indicator_demo.py shows how to use Indicator(name, fn) for pre-computation and indicator_factory for incremental updates.

    Advanced Backtesting

    • Multi-Asset/Frequency: 04_mixed_assets.py for mixed assets and 14_multi_frequency.py for multi-frequency backtesting using DataFeedAdapter replay.
    • Warm Start: 21_warm_start_demo.py for general warm starts and 56_functional_warm_start_demo.py for functional on_resume(ctx) implementations.
    • Walk-Forward Optimization (WFO): 12_wfo_integrated.py provides an integrated WFO example.
  3. Develop strategies by inheriting from `akquant.Strategy`

    main

    To create a custom trading strategy, inherit from the akquant.Strategy base class and override the appropriate callback methods to define your logic.

    Core Lifecycle Callbacks:

    • on_start(): Initialize subscriptions (subscribe) and indicators.
    • on_bar(bar): Logic triggered when a Bar closes.
    • on_tick(tick): Logic triggered when a Tick arrives.
    • on_order(order) / on_trade(trade): Handle order state changes and trade reports.
    • on_stop(): Cleanup when the strategy stops.

    Advanced Timing Callbacks:

    • on_pre_open(event): Triggered before the first regular event of the day. Use this for "pre-open decision, current open fill" workflows. By default, orders placed here use NextOpen() semantics.
    • on_before_trading(trading_date, timestamp): Triggered at the start of a regular session. Follows a "previous trading day / previous snapshot only" visibility model.
    • on_cross_section(trading_date, timestamp): A same-cycle rebalance hook that runs after the first complete cross-symbol bar slice of the day. It can see the current day's bar history and account snapshot.
    • on_expiry(event): Triggered after an expiry_date driven settlement/removal is executed.
  4. Understand AKQuant Time and Timezone Handling

    main

    To avoid confusion between local log timestamps and UTC fields (such as timestamp_iso), follow the core rule of the AKQuant framework:

    AKQuant stores factual event time in UTC and renders local time for humans.

    For detailed implementation details, refer to the following guides:

    • Intro explanation: AKQuant Time and Timezones
    • Advanced FAQ: Timezone Handling Guide
  5. How to implement cross-sectional rotation strategies

    main

    AKQuant provides several patterns for executing cross-sectional (multi-symbol) rotation logic depending on when you want the strategy to trigger:

    • on_before_trading (Daily Boundary): Triggered at the start of a trading day. The callback only sees the snapshot from the previous trading day/account state. Best for daily preparation and unified rebalancing.
    • on_bar with Time-Slice Bucketing: If you don't use a timer, you can implement a manual bucket in on_bar. Use a cache (e.g., timestamp -> set(symbol)) to detect when all symbols for a specific timestamp have arrived, then execute the cross-sectional scoring and rebalancing once.
    • on_timer (Scheduled): Use schedule_daily() to coordinate with on_timer(). This decouples cross-sectional logic from individual bar updates and is recommended for stable, production-style rebalancing at fixed points.
    • on_cross_section (Intraday/Post-Bar): Triggered after the first complete cross-sectional slice of the day. This callback can see both historical data and the current account snapshot. Ideal for rebalancing based on closing prices or full-day cross-sectional data.
  6. Choose the right scope for custom indicators

    main

    Before implementing a custom indicator, determine your goal to select the correct implementation path in AKQuant:

    GoalRecommended pathTypical API
    Add a private signal to a strategycustom Indicator / custom incremental objectregister on Strategy
    Compute a full series from a DataFrameindicator_mode="precompute"register_precomputed_indicator(...)
    Maintain state bar by barindicator_mode="incremental"register_incremental_indicator(...)
    Add a new name to akquant.talibmodify the compatibility layer sourcenot runtime plugin registration

    If you only need a signal for a specific strategy, do not attempt to extend akquant.talib; instead, register it directly on your Strategy instance.

  7. Implement an ML Strategy with Walk-Forward Validation

    main

    AKQuant provides a structured workflow for Machine Learning strategies using akquant.ml.QuantModel and adapters like SklearnAdapter or PyTorchAdapter.

    Workflow:

    1. Initialization: In __init__, initialize self.model with an adapter.
    2. Configuration: Use self.model.set_validation(...) to configure Walk-Forward Validation. This automates rolling windows and training triggers.
    3. Feature Engineering: Implement prepare_features(self, df, mode):
      • mode='training': Return (X, y). Ensure y (e.g., shifted returns) is aligned with X and drop NaNs.
      • mode='inference': Return X (the features for the current bar).
    4. Training: The framework automatically triggers on_train_signal $\rightarrow$ prepare_features(mode='training') $\rightarrow$ model.fit().
    5. Inference: In on_bar, check self.is_model_ready() and self.current_validation_window(), then call prepare_features(mode='inference') and model.predict().
    6. Lifecycle: Training occurs on the current bar, but the model activates on the next bar. The framework calls model.clone() for each training window.

    Key Validation Parameters for set_validation:

    • method: e.g., 'walk_forward'.
    • train_window: Duration for training (e.g., '200d').
    • test_window: Planned Out-of-Sample (OOS) range (e.g., '30d').
    • rolling_step: Frequency of retraining (e.g., '30d').
    from akquant import Strategy, Bar
    from akquant.ml import SklearnAdapter
    from sklearn.ensemble import RandomForestClassifier
    import pandas as pd
    import numpy as np
    
    class MLStrategy(Strategy):
        def __init__(self):
            # 1. Initialize Adapter
            self.model = SklearnAdapter(RandomForestClassifier(n_estimators=10))
    
            # 2. Configure Walk-Forward (Auto-Training)
            self.model.set_validation(
                method='walk_forward',
                train_window='200d',
                test_window='30d',
                rolling_step='30d',
                frequency='1d',
                verbose=True
            )
    
        def prepare_features(self, df: pd.DataFrame, mode: str = "training"):
            df['ret1'] = df['close'].pct_change()
            df['ret5'] = df['close'].pct_change(5)
            df['vol_change'] = df['volume'].pct_change()
            features = ['ret1', 'ret5', 'vol_change']
    
            if mode == 'inference':
                return df[features].iloc[-1:].fillna(0)
    
            df['target'] = (df['close'].shift(-1) > df['close']).astype(int)
            data = df.dropna()
            return data[features], data['target']
    
        def on_bar(self, bar: Bar):
            window = self.current_validation_window()
            if window is None or not self.is_model_ready():
                return
    
            hist_df = self.get_history_df(30)
            if len(hist_df) < 10:
                return
    
            X_curr = self.prepare_features(hist_df, mode='inference')
    
            try:
                pred = self.model.predict(X_curr)[0]
                pos = self.get_position(bar.symbol)
                if pred == 1 and pos == 0:
                    self.buy(bar.symbol, 1000)
                elif pred == 0 and pos > 0:
                    self.sell(bar.symbol, pos)
            except Exception:
                pass
  8. How Warm Start works in AKQuant

    main

    Warm Start allows you to save the state of a backtest (snapshot) and resume it later with new data. This is useful for segmented backtests or long-horizon runs where you want to avoid rebuilding state from scratch.

    What is saved in a snapshot:

    • Dynamic runtime state: Portfolio, Orders, strategy attributes, and indicator state.
    • Strategy-level risk state: Limits, cashflow, daily-loss baseline, drawdown peak, and reduce-only activation state.
    • History buffers: get_history() and get_history_map() resume with the rolling window from the previous phase intact.

    What is NOT saved (must be reconfigured):

    • Static configuration: Instrument and MarketModel settings.
    • Trading rules: Fee settings (commission_rate, stamp_tax_rate, transfer_fee_rate), t_plus_one status, and commission_policy.
    • Timezone: Defaults to Asia/Shanghai if not explicitly provided during resume.
  9. How Golden Tests work in AKQuant

    main

    Golden Tests are integration tests that use Synthetic Data to simulate specific market scenarios (e.g., T+1, Limit Up/Down, Option Exercise).

    Instead of just checking code logic, they compare backtest outputs (equity curves, trade records, and metrics) against a locked Baseline (Standard Answers). This ensures that algorithmic changes do not unintentionally alter expected backtest results.

    Key scenarios included:

    • stock_t1: Verifies T+1 trading rules (e.g., Day 1 buy -> Day 2 sell allowed; Day 3 buy -> Day 3 sell rejected).
    • futures_margin: Verifies margin requirements (e.g., rejecting a 2nd lot purchase due to insufficient capital).
    • option_basic: Verifies option contract lifecycle and PnL calculation.
  10. Understand configuration layering and precedence

    main

    The backtesting engine uses a layered configuration system. If a setting is defined at multiple levels, the higher-level setting overrides the lower-level one. The precedence order from highest to lowest is:

    1. Order-level: Specific settings applied to an individual order.
    2. Strategy-map level: Settings defined via strategy_* prefixes.
    3. Run-level: Settings applied to the entire backtest execution.
    4. Market defaults: The baseline settings for the market.
  11. How to perform multi-symbol backtesting

    main

    AKQuant supports backtesting across multiple symbols simultaneously.

    1. Data Input: Pass a dictionary to the data parameter of run_backtest where keys are symbols and values are their corresponding pandas.DataFrame objects: {symbol: DataFrame}.
    2. Data Access: Within your strategy, use self.get_history(..., symbol=s) to retrieve data for a specific symbol s from the provided dataset.