Meeken 的杂物间

14 object(s)
 

北向资金量化交易策略

思路

通过聚宽平台提供的数据接口,跟踪北向资金出入数据,追涨来实现套利。代码获取了每日的北向流入额,然后用 150 日的流入额做出了一个布林带,当流入额大于等于布林带上轨的时候,策略会跟踪北向持仓中股票自身占比最大的 15 只股票,然后把他们买入,并且卖出自己持仓中不在这 15 只股票。当流入额小于等于布林带下轨时,清仓卖出。

代码

from jqdata import *
import random
import pandas as pd
import numpy as np
import datetime as dt

# 初始化函数,设定基准等等
def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 输出内容到日志 log.info()
    log.info('初始函数开始运行且全局只运行一次')
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')

    ### 股票相关设定 ###
    # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5),
                   type='stock')
    g.max_stock_count = 15
    g.buy_pool = []
    g.sale_pool = []
    g.top_money_in = []
    g.window = 90
    g.stdev_n = 1
    g.mf, g.upper, g.lower = None, None, None
    run_daily(before_market_open, time='07:00')
    run_daily(reblance, '9:30')

def before_market_open(context):
    g.buy_pool = []
    g.sale_pool = []
    pre_date = (context.current_dt - datetime.timedelta(1)
                ).strftime('%Y-%m-%d')
    g.mf, g.upper, g.lower = get_boll(pre_date)
    log.info('北上资金均值:%.2f  北上资金上界:%.2f 北上资金下界:%.2f' % (g.mf, g.upper, g.lower))

def get_boll(end_date):
    """
    获取北向资金布林带
    """
    # 数据表:北上资金某日成交额
    table = finance.STK_ML_QUOTA
    # 查询:日期,每日额度,每日余额
    q = query(
        table.day, table.quota_daily, table.quota_daily_balance
    ).filter(
        table.link_id.in_(['310001', '310002']), table.day <= end_date
    ).order_by(table.day)
    money_df = finance.run_query(q)
    # 每日额度 - 每日余额
    money_df['net_amount'] = money_df['quota_daily'] - \
        money_df['quota_daily_balance']
    # 分组求和
    money_df = money_df.groupby('day')[['net_amount']].sum().iloc[-g.window:]
    mid = money_df['net_amount'].mean()
    stdev = money_df['net_amount'].std()
    upper = mid + 1*g.stdev_n * stdev
    lower = mid - 0.17*g.stdev_n * stdev
    mf = money_df['net_amount'].iloc[-1]
    return mf, upper, lower

def calc_change(context):
    # 数据表:北上资金持有股票数据
    table = finance.STK_HK_HOLD_INFO
    # 查询:日期,名称,代码,持股比例
    q = query(table.day, table.name, table.code, table.share_ratio).filter(
        table.link_id.in_(['310001', '310002']), table.day.in_([context.previous_date]))
    # 获取查询数据结果
    df = finance.run_query(q)
    # 将结果数据集根据持股比例进行降序排序,选出前x只股,x即为 g.max_stock_count 的值,返回结果
    return df.sort_values(by='share_ratio', ascending=False)[:g.max_stock_count]['code'].values

### 每日比较算法 ###
def reblance(context):
    if g.mf >= g.upper:
        s_change_rank = calc_change(context)
        final = list(s_change_rank)
        current_hold_funds_set = set(context.portfolio.positions.keys())
        if set(final) != current_hold_funds_set:
            need_buy = set(final).difference(current_hold_funds_set)
            need_sell = current_hold_funds_set.difference(final)
            cash_per_fund = context.portfolio.total_value/g.max_stock_count*0.99
            for fund in need_sell:
                # order_target(fund, 0)
                add_to_sale_pool(fund)
            for fund in need_buy:
                # order_value(fund, cash_per_fund)
                add_to_buy_pool(fund, cash_per_fund)
        

    elif g.mf <= g.lower:
        current_hold_funds_set = set(context.portfolio.positions.keys())
        if len(current_hold_funds_set) != 0:
            for fund in current_hold_funds_set:
                #log.info('买入 %s' % fund.name)
                # order_target(fund, 0)
                add_to_sale_pool(fund)
           
### 当天卖出队列 ###
def add_to_sale_pool(security_code):
    if len(g.sale_pool) <= g.max_stock_count:
        g.sale_pool.append(security_code)
    
### 当天买入队列 ###
def add_to_buy_pool(security_code, cash):
    if len(g.sale_pool) <= g.max_stock_count:
        g.buy_pool.append({'code': security_code, 'cash': cash})
        log.info(g.buy_pool)

### 买卖策略 ###
'''
测试时暂时空仓
'''
def handle_data(context):
    if len(g.buy_pool) > 0:
        length = len(g.buy_pool)
        idx = 0
        while length > 0:
            buy_item = g.buy_pool[idx]
            order_value(buy_item['code'], buy_item['cash'])
            del g.buy_pool[idx]
            length = length - 1

    elif len(g.sale_pool) > 0:
        length = len(g.sale_pool)
        idx = 0
        while length > 0:
            sale_code = g.sale_pool[idx]
            order_target(sale_code, 0)
            del g.sale_pool[idx]
            length = length - 1