Skip to content

Writing Strategies

Overview

Item Description
Goal Understand the strategy skeleton and write your first strategy
Prerequisite Installation & Quick Start

1. Quick Start: Write and Run a Strategy

A runnable strategy must contain at least: initialize(context) (initialization) and a trading function registered with run_daily.

from eqlib import *

def initialize(context):
    g.security = '601390'          # Industrial and Commercial Bank of China
    set_benchmark('000300.XSHG')   # CSI 300 as benchmark
    set_option('use_real_price', True)
    run_daily(market_open, time='every_bar')

def market_open(context):
    hist = attribute_history(g.security, 20, '1d', ['close'])
    ma20 = hist['close'].mean()
    current_price = hist['close'].iloc[-1]

    if current_price > ma20 * 1.02:
        order_value(g.security, context.portfolio.available_cash)
    elif current_price < ma20 * 0.98 and context.portfolio.positions.get(g.security):
        order_target(g.security, 0)

result = run_strategy(
    initialize,
    start_date='2024-01-01',
    end_date='2024-12-31',
    starting_cash=100000,
    benchmark='000300.XSHG',
    securities=['601390'],
    report_dir='reports',
)

After running, four report files will be generated: PNG, HTML, Markdown, and JSON. Open the .html file in a browser first to view the complete report.

Order execution model: The order* API series only places orders in the current callback; actual execution occurs at the next trading day's opening price.


2. Strategy Lifecycle

initialize(context)          ← Called once at the start of the backtest
    |
    v
before_trading_start(ctx, data)   ← Called before market open on each trading day (optional)
    |
    v
run_daily / run_weekly / run_monthly scheduled functions
    |
    v
handle_data(context, data)   ← Called once per trading day
    |
    v
after_trading_end(ctx, data) ← Called after market close on each trading day (optional)

2.1 initialize(context)

The strategy entry point. Every strategy must define this function.

def initialize(context):
    g.security = '601390'
    set_benchmark('000300.XSHG')
    set_order_cost(OrderCost(
        open_tax=0,
        close_tax=0.0005,
        open_commission=0.00025,
        close_commission=0.00025,
        min_commission=5,
    ))
    run_daily(market_open, time='every_bar')

2.2 handle_data(context, data)

Daily trading logic. Can also be replaced with run_daily.

def handle_data(context, data):
    bar = data.get(g.security)
    if bar:
        log.info("%s today's close: %.2f" % (g.security, bar.close))

2.3 Pre-market / Post-market Callbacks

from eqlib import before_trading_start, after_trading_end

def before_start(context, data):
    log.info("Pre-market check...")

def after_end(context, data):
    log.info("Post-market summary: holding %d stocks" % len(context.portfolio.positions))

before_trading_start(before_start)
after_trading_end(after_end)

2.4 g Global Object

g is strategy-level persistent storage that remains valid across trading days.

def initialize(context):
    g.security = '601390'
    g.hold_days = 0

def market_open(context):
    g.hold_days += 1