Skip to content

均值回复策略

python
# 均值回复策略

from zltquant import *
from datetime import *
def initialize(context):
    # 设定基准
    set_benchmark('sz399300')

    # 输出内容到日志 log.info()
    log.info('初始函数开始运行且全局只运行一次')

    run_daily(after_market_close, time='15:30')
    run_monthly(adjust_position, monthday=1, time='10:30')
    
    g.observe_days = 20       #收益率观察交易日数
    g.target_value = 10000    #每只股票金额
    g.stock_number = 10       #单方向股票数量

# 调仓
def adjust_position(context):
    stocks = get_index_stocks('sz399300')
    stocks = filter_stocks(context, stocks)
    df = get_price(stocks, count=g.observe_days, end_date=context.current_dt, frequency='1d', fields=['close'],fq='pre',df=True)
    
    #按历史收益率排序
    grouped = df.groupby('security').agg({
        'close': ['first', 'last']
    }).reset_index()
    grouped.columns = ['code', 'start_price', 'end_price']
    grouped['return'] = (grouped['end_price'] - grouped['start_price']) / grouped['start_price']
    grouped_sorted = grouped.sort_values(by='return', ascending=True)
    
    bad_list = grouped_sorted['code'][:g.stock_number]
    good_list = grouped_sorted['code'][-g.stock_number:]
    
    log.info('表现差的股票:%s' % bad_list)
    log.info('表现好的股票:%s' % good_list)
    
    # 均值回复策略
    new_long_list = bad_list
    new_short_list = good_list
    
    # 当前的组合仓位信息
    portfolio = context.portfolio
    long_positions = list(portfolio.positions.keys())
    log.info("positions", long_positions)

    # 多头平仓
    for stock in long_positions:
        if stock not in new_long_list:
            amount = portfolio.positions[stock].closeable_amount
            log.info("多头平仓,股票:%s" % stock)
            order(stock, -amount)
            
            
    # 多头开仓
    for stock in new_long_list:
        if stock not in long_positions:
            log.info("多头开仓,股票:%s" % stock)
            order_target_value(stock, g.target_value)
            
            
#过滤各种股票
def filter_stocks(context, stock_list):
    filtered_stocks = []
    for stock in stock_list:
        stock_code = stock[2:]
        if stock_code.startswith('30') or stock_code.startswith('68') or stock_code.startswith('8') or stock_code.startswith('4'):  # 市场类型
            continue
        start_date = get_security_info(stock).start_date   
        if context.previous_date - start_date < timedelta(days=375):
            continue
        filtered_stocks.append(stock)
    return filtered_stocks

## 收盘后运行函数
def after_market_close(context):
    p = context.portfolio
    log.info('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')
    log.info('总资产:', p.total_value)
    log.info('##############################################################')

if __name__ == '__main__':
    run_main()

文档版本: 1.0.0 | 发布于 2025-01-29