返回列表 发帖

[原创代码] [Python]北上资金持仓市值排序跟踪策略

本帖最后由 老刘1号 于 2023-3-3 12:32 编辑

论坛正好有python板块,发来玩玩
回测环境:聚宽量化
import talib
from prettytable import PrettyTable
import pandas
import datetime
import time
from jqdata import *
def initialize(context):
    # 初始化变量
    g.buy_stock_count = 20
    # 设定基准为沪深300
    set_benchmark('000300.XSHG')
    # True为开启动态复权模式,使用真实价格交易
    set_option('use_real_price', True)
    # 设定避免未来函数模式
    set_option("avoid_future_data", True)
    # 股票类交易手续费和滑点
    set_order_cost(
        OrderCost(
        open_tax        =0,
        close_tax       =0.001,
        open_commission =0.0003,
        close_commission=0.0003,
        min_commission  =5),
        type            ='stock')
    set_slippage(FixedSlippage(0.02))
    # 设置日志级别
    log.set_level('order', 'error')
    # 每天运行
    run_daily(daily,'open')
def daily(context):
    adjust_position(context, select_stocks(context))
        
def select_stocks(context):
    #沪深股通持仓
    df=finance.run_query(
        query(finance.STK_HK_HOLD_INFO)\
        .filter(finance.STK_HK_HOLD_INFO.day>=context.previous_date)\
        .filter(finance.STK_HK_HOLD_INFO.link_id.in_([310001,310002])))
    stocks = [ {
            'code' : code,
            'name' : name,
            'number' : share_number,
            'price' : price,
            'value' : share_number * price
        } for code, name, share_number, price in zip(
        list(df.code), \
        list(df.name), \
        list(df.share_number), \
        list(get_price(
            security=list(df.code),
            panel=False,
            start_date=context.previous_date,
            end_date=context.previous_date,
            frequency='daily',
            fields='close',
            skip_paused=False,
            fq='pre')['close'])
    )]
    #按持仓市值排序
    stocks = sorted(stocks, key = lambda stock: stock['value'], reverse=True)
    #for stock in filter((lambda x: x['price'] < 200), stocks[:40]):
        #print("{} {} {} {}".format(stock['code'], stock['name'], stock['value'], stock['price']))
    #print([i['code'] for i in filter((lambda x: x['price'] < 200), stocks[:40])])
    return [stock['code'] for stock in stocks][:g.buy_stock_count]
        
def filter_paused_and_st_stock(stock_list):
    current_data = get_current_data()
    return [stock for stock in stock_list if not current_data[stock].paused
    and not current_data[stock].is_st and 'ST' not in current_data[stock].
    name and '*' not in current_data[stock].name and '退' not in current_data[stock].name]
   
def adjust_position(context, buy_stocks):
    # 现持仓的股票,如果不在“目标池”中,且未涨停,就卖出
    if len(context.portfolio.positions)>0:
        last_prices = history(1, '1m', 'close', security_list=list(context.portfolio.positions.keys()))
        for stock in list(context.portfolio.positions.keys()):
            if stock not in buy_stocks :
                curr_data = get_current_data()
                if last_prices[stock][-1] < curr_data[stock].high_limit:
                    order_target_value(stock, 0)
    # 依次买入“目标池”中的股票            
    for stock in buy_stocks:
        position_count = len(context.portfolio.positions)
        if g.buy_stock_count > position_count:
            value = context.portfolio.cash / (g.buy_stock_count - position_count)
            if context.portfolio.positions[stock].total_amount == 0:
                stock_price = get_price(
                    security=stock,
                    panel=False,
                    start_date=context.previous_date,
                    end_date=context.previous_date,
                    frequency='daily',
                    fields='close',
                    skip_paused=False,
                    fq='pre')['close']
                order(stock, (((context.portfolio.available_cash+context.portfolio.positions_value+ context.portfolio.returns)/g.buy_stock_count)/stock_price)//100*100)
               
def show_stock(stock):
    '''
    获取股票代码的显示信息   
    :param stock: 股票代码,例如: '603822.SH'
    :return: str,例如:'603822 嘉澳环保'
    '''
    return "%s %s" % (stock[:6], get_security_info(stock).display_name)
   
def get_portfolio_info_text(context,new_stocks,op_sfs=[0]):
    # new_stocks是需要持仓的股票列表
    sub_str = ''
    table = PrettyTable(["仓号","股票", "持仓", "当前价", "盈亏率","持仓比"])  
    for sf_id in range(len(context.subportfolios)):
        cash = context.subportfolios[sf_id].cash
        p_value = context.subportfolios[sf_id].positions_value
        total_values = p_value +cash
        if sf_id in op_sfs:
            sf_id_str = str(sf_id) + ' *'
        else:
            sf_id_str = str(sf_id)
        for stock in list(context.subportfolios[sf_id].long_positions.keys()):
            position = context.subportfolios[sf_id].long_positions[stock]
            if sf_id in op_sfs and stock in new_stocks:
                stock_str = show_stock(stock) + ' *'
            else:
                stock_str = show_stock(stock)
            stock_raite = (position.total_amount * position.price) / total_values * 100
            table.add_row([sf_id_str,
                stock_str,
                position.total_amount,
                position.price,
                "%.2f%%"%((position.price - position.avg_cost) / position.avg_cost * 100),
                "%.2f%%"%(stock_raite)]
                )
        if sf_id < len(context.subportfolios) - 1:
            table.add_row(['----','---------------','-----','----','-----','-----'])
        sub_str += '[仓号: %d] [总值:%d] [持股数:%d] [仓位:%.2f%%] \n'%(sf_id, total_values,
            len(context.subportfolios[sf_id].long_positions), p_value*100/(cash+p_value))
    log.info('持仓详情:\n' + sub_str + str(table))COPY
回测数据
回测时间
2022-02-08 20:20:53
回测区间
2017-03-20 - 2022-02-07
策略收益
129.20%
策略年化收益
19.07%
超额收益
70.43%
基准收益
34.48%
阿尔法
0.128
贝塔
0.915
夏普比率
0.759
胜率
0.846
盈亏比
13.917
最大回撤
28.29%
索提诺比率
1.082
日均超额收益
0.05%
超额收益最大回撤
13.77%
超额收益夏普比率
0.857
日胜率
0.536
盈利次数
11
亏损次数
2
信息比率
1.376
策略波动率
0.199
基准波动率
0.193
最大回撤区间
2021/02/10,2022/01/28COPY
1

评分人数

本帖最后由 523066680 于 2023-3-2 23:23 编辑

好多名词还没弄明白,为什么有些用了未来函数的指标看起来很准?
为什么很多人在指标市场里明确不要带未来函数的指标?
[url=][/url]

TOP

本帖最后由 老刘1号 于 2023-3-3 00:06 编辑

回复 2# 523066680


    未来函数就是在当时那个时间点获取不了的数据,比如说在早盘的时候获得当天的晚间新闻
有的时候未来函数也会比较隐蔽,比如说我写一个策略,在12年全仓茅台,然后获得了很不错的收益,
虽然看似在程序中没有用到任何未来函数,但是其实我知道茅台会涨(这是一个后验的指标,当时肯定不知道),所以这也算一种未来函数
只要量化模型内用了未来函数,可以说模型就是完全无效的

其实量化交易用历史数据训练模型本身也有很大的问题,它的大假设就是历史会机械重复,实际上不一定
而且某种程度上来说,量化模型不触及商业的本质,很多投资大师都是靠实地调研获取一些“不能量化”的数据,
从经济学的角度来说,信息不对称才能赚钱,网上数据都是公开的,大家信息差很小,训练的模型都差不多,那么可操作的空间就很小
所以我后面也没再深入研究了

当然高频量化(做市商)和手动交易转机器交易还是有意义的,
不过前面的已经很卷了,都是大佬用自己做的FPGA,放到离交易所很近的机房里面,进行微秒级别的交易
后边的话,就是如果有固定的策略,而且懒得手动操作的话,可以写成程序帮忙交易
我发的python代码其实就属于第二种,不过我觉得还是直接买几个量化基金和历史业绩优秀的主动基金比较好,所以没有实盘
1

评分人数

    • 523066680: 感谢分享,少走很多弯路PB + 18

TOP

回复 2# 523066680


    推荐一篇文:
https://blog.csdn.net/weixin_42219751/article/details/102658975

TOP

不怕哪天程序抽风突然开始乱买?(虽然不太可能)
你好

TOP

返回列表