返回列表 发布新帖

量化研究--雪球交易系统问题深度解析修改

文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途,

这几天用户反馈雪球交易系统重复下单的情况,我对着数据详细分析,完成了问题的修改,mini的为例子,建议使用大qmt的,详细问题分析的视频

我全部同步了网页直接下载就可以

5883041c08d9e4511bb73e2c433594d3.png

大qmt的简单一点

a6d9be4ba52ef021abb9257dd4329314.png

mini的合适深度研究原理

daebd3f1eff8510ae67fccf08b8395a2.png

miniqmt的,代码复杂

fcbd0a88ed04a9460e6407eeebb961ab.png

76142ae6e5a0b3f19033e08c72d85021.png

252b1e1f81cc036d5e0ed2bf04c29f45.png

生成的原因1,非交易时间的委托,交易时间是9点15到11:30,下午的1点到3点,其他的时间委托都是不是交易时间,雪球跳仓会生成应该委托id,但是成交的时候又会生成一个,相当于一个单子,生成了2个id,就会下2次单子,我们可以利用成交价格为空剔除不是交易时间的单子,等待成交了在读取,就可以避免二次下单,实时记录交易id变化

aa5691965ff14edbe16ad4eedb0637d0.png

de9bb6a05a986ca744afc0a585111968.png

2交易取消,当用户取消委托下单,也会生成一个交易,单子这个id是无法识别是不是下单成功了就会生成了一个真正的单子qmt读取到就会下单,所以利用成交价格剔除,没有真正委托,撤单的单子

d075510ac86b6fa833d75b4c8b0d8d22.png

3/废单数据/取消交易数据,这个就好理解,比如纳斯达克ETf是T0的,但是雪球是T1交易,资金不能马上回来,调仓其他的标的就会废单,被雪球取消交易,但是程序会读取到这个委托就会下载,这个问题利用成交价格没有剔除就可以

d8aee5068246017e0bc9c8de48ee9cf9.png

点击右上角的运行分析一下就可以,看分析的结果数据完美

bef29afa3ab709691e9abc16edbc55be.png

*********************************************************
雪球委托成功的交易数据*********************
Empty DataFrame
Columns: [名称, 证券代码, price, 调整比例, 调整比例1, 交易类型, id, 组合名称, 组合id, 投资备注, 更新时间, 买入黑名单, 删除id, 非交易时间委托]
Index: []
雪球非交易时间委托数据/撤单数据/废单数据/取消交易数据不跟踪****************
           名称    证券代码  price   调整比例   调整比例1  ...                 投资备注        更新时间 买入黑名单             删除id 非交易时间委托
4      新能源ETF  516160      0   9.39    9.39  ...   xqB516160244507222  2025-12-04    不是    516160,9.39,B       是
3      半导体ETF  512480      0 -16.98  -16.98  ...   xqS512480244507220  2025-12-04    不是  512480,-16.98,S       是
2    创业板50ETF  159949      0   0.00     0.0  ...  xq不变159949244507218  2025-12-04    不是    159949,0.0,不变       是
1    纳指100ETF  513390      0   8.74    8.74  ...   xqB513390244507215  2025-12-04    不是    513390,8.74,B        是
0  纳斯达克100ETF  513110      0   9.00     9.0  ...   xqB513110244507212  2025-12-04    不是     513110,9.0,B       是


[5 rows x 14 columns]

委托没有成交的数据不跟单,非交易时间的委托,等待明天开盘安成交id跟踪交易

f9520b444d37a621f5d42790ac702c01.png

下单的测试结果

545bf1d1b9e574d2021dc06b8012d6c4.png

源代码我全部上传了知识星球直接下载使用就可以

73211b312dc755f2c55a819201e3f17e.jpg

不懂的问我就可以,加我备注入群可以加入量化群

083bb52c2810a60a2a0a51cfa7160c31.jpg

完整的带没找我就可以,参考框架学习

from trader_tool.unification_data import unification_data
from trader_tool.trader_frame import trader_frame
import pandas as pd 
import time
from datetime import datetime
import schedule
import json
from trader_tool.base_func import base_func
import os
from trader_tool.xueqiou_data import xueqie_data
from trader_tool.seed_trader_info import seed_trader_info
import random
import math
from trader_tool.decode_trader_password import decode_trader_password
class joinquant_trader:
    def __init__(self,
                trader_tool='ths',
                exe='C:/同花顺软件/同花顺/xiadan.exe',
                tesseract_cmd='C:/Program Files/Tesseract-OCR/tesseract',
                qmt_path='D:/国金QMT交易端模拟/userdata_mini',
                qmt_account='55009640',
                qmt_account_type='STOCK',
                data_api='qmt'):
        '''
        索普量化雪球交易系统
        作者:索普量化
        微信:xms_quants1
        时间:20251023
        '''
        print('################################################################################################')
        print("""
        风险提示:
        1.以下为量化交易模型,主要内容来源于互联网学习加工,分享的核心是交易思路框架,标的范围和参数仅为学习输出的举例,不能直接运用于交易。
        2.思路框架仅供学习参考,各位投资者朋友需根据自己的需求搭建自己的交易体系和具体策略。
        3.量化交易过程中可能涉及数据准确性、系统BUG、操作不当等风险,交易之前请务必自行充分学习。股市有风险,投资需谨慎和自主决策!
              """)
        print('################################################################################################')
        self.data_api=data_api
        self.exe=exe
        self.tesseract_cmd=tesseract_cmd
        self.trader_tool=trader_tool
        self.qmt_path=qmt_path
        self.qmt_account=qmt_account
        self.qmt_account_type=qmt_account_type
        order_frame=trader_frame(
            trader_tool=self.trader_tool,
            exe=self.exe,
            tesseract_cmd=self.tesseract_cmd,
            qmt_path=self.qmt_path,
            qmt_account=self.qmt_account,
            qmt_account_type=self.qmt_account_type,
            )
        self.trader=order_frame.get_trader_frame()
        data=unification_data(trader_tool=self.trader_tool,data_api=self.data_api)
        self.data=data.get_unification_data()
        self.path=os.path.dirname(os.path.abspath(__file__))
        self.password=decode_trader_password()
    def connact(self):
        '''
        链接交易
        '''
        try:
            self.trader.connect()
            return True
        except Exception as e:
            print("运行错误:",e)
            print('{}连接失败'.format(self.trader_tool))
            return False
    def save_data(self):
        try:
            account=self.trader.balance()
            account.to_excel(r'{}/账户数据/账户数据.xlsx'.format(self.path))
            print(account)
            position=self.trader.position()
            position.to_excel(r'{}/持股数据/持股数据.xlsx'.format(self.path))
            print(position)
        except Exception as e:
            print(e,'账户路径检测,没有链接成功*************')
    def get_trader_adjust_data(self,name='西蒙斯测试',zh='ZH3368671'):
        '''
        获取交易
        '''
        with open('{}/策略配置.json'.format(self.path),'r+',encoding='utf-8') as f:
            com=f.read()
        text=json.loads(com)
        st_name=text['策略名称']
        test=text['是否测试']
        n=text['测试长度']
        buy_not_list=text['买入黑名单']
        st_name=text['策略名称']
        u=text['雪球U值']
        token=text['雪球token']
        sp_time=text['错误随机等待时间']
        now_date=str(datetime.now())[:10]
        api=xueqie_data(u=u,xq_a_token=token,assembly_id=zh)
        stats,df=api.get_hist_move()
        if stats==False:
            random_n=random.randint(1,sp_time)
            time.sleep(random_n)
            print(name,'速度太快随机等待时间{}****************'.format(random_n))
        else:
            pass
        if df.shape[0]>0:
            df['updated_at']=pd.to_datetime(df['updated_at'],unit='ms')
            df['created_at']=pd.to_datetime(df['created_at'],unit='ms')
            df['updated_at']=df['updated_at'].apply(lambda x:str(x)[:10])
            df['id']=df['id'].astype(str)
            df['更新时间']=df['updated_at']
            df['名称']=df['stock_name']
            df['证券代码']=df['stock_symbol'].apply(lambda x: str(x)[2:])
            df['买入黑名单']=df['证券代码'].apply(lambda x: '是' if x in buy_not_list else '不是')
            df['prev_weight_adjusted']=df['prev_weight_adjusted'].fillna(0)
            df['调整比例']=df['target_weight']-df['prev_weight_adjusted']
            df['交易类型'] =df['调整比例'].apply(lambda x: 'B' if x > 0 else '不变' if x == 0 else 'S')
            df=df.sort_values(by='created_at',ascending=True)
            df['组合名称']=name
            df['组合id']=zh
            df['投资备注']=st_name+df['交易类型']+df['证券代码']+df['id']
            df['调整比例1']=df['调整比例'].apply(lambda x: str(x)[:len(str(x).split('.')[0])+3])
            df=df[['名称',"证券代码",'price','调整比例','调整比例1','交易类型','id',
                    '组合名称','组合id','投资备注','更新时间']]
            df['买入黑名单']=df['证券代码'].apply(lambda x :"是" if x in buy_not_list else '不是')
            df=df[df['买入黑名单']=='不是']
            if test=='是':
                print('开启测试模型,实盘改成是不开启测试')
                df=df[-n:]
            else:
                df=df[df['更新时间']==now_date]
        else:
            df=pd.DataFrame()
        if df.shape[0]>0:
            df['删除id']=df['证券代码'].astype(str)+','+df['调整比例1'].astype(str)+','+df['交易类型'].astype(str)
            df=df.drop_duplicates(subset=['删除id'],keep='last')
            df.to_excel(r'数据测试.xlsx')
            #下面这个代码启动,相同的标的,相同交易类型只交易一次
            #df['删除id2']=df['证券代码'].astype(str)+','+df['交易类型'].astype(str)
            #df=df.drop_duplicates(subset=['删除id2'],keep='last')
            print('*****{}今天有跟单数据*********'.format(now_date))
            print('*********************************************************')
            df['price']=df['price'].fillna(0)
            df['非交易时间委托']=df['price'].apply(lambda x: '是' if x==0 else '不是')
            not_trader=df[df['非交易时间委托']=='是']
            df=df[df['非交易时间委托']=='不是']
            print('雪球委托成功的交易数据*********************')
            print(df)
            print('雪球非交易时间委托数据/撤单数据/废单数据/取消交易数据不跟踪****************')
            print(not_trader)
        else:
            print('*****{}今天没有跟单数据*********'.format(now_date))
        
        return df
    def select_data_type(stock='600031.SH'):
        '''
        选择数据类型
        '''
        stock=str(stock)
        if stock[:2] in ['11','12'] or stock[:3] in ['123','110','113','123','127','128','118','132','120']:
            return 'bond'
        elif stock[:2] in ['51','15','50','16','18','52']:
            return 'fund'
        else:
            return 'stock'
    def get_price(self,stock='513100'):
        '''
        获取价格
        '''
        price=self.data.get_spot_data(stock=stock)['最新价']
        return price
    def check_is_sell(self,stock='562310',amount=100):
        '''
        检查是否可以卖出
        '''
        position=self.trader.position()
        if position.shape[0]>0:
            position=position[position['证券代码']==stock]
            if position.shape[0]>0:
                position=position[position['股票余额']>=10]
                if position.shape[0]>0:
                    hold_amount=position['股票余额'].tolist()[-1]
                    av_amount=position['可用余额'].tolist()[-1]
                    if av_amount>=amount and amount>=10:
                        return True
                    elif av_amount< amount and av_amount>=10:
                        return True
                else:
                    return False
            else:
                return False
        else:
            return False
    def check_is_buy(self,stock='513100.SH',amount=100,price=1.3):
        '''
        检查是否可以买入
        '''
        account=self.trader.balance()
        #可以使用的现金
        av_cash=account['可用金额'].tolist()[-1]
        value=amount*price
        if av_cash>=value:
            return True
        else:
            return False
    def adjust_amount(self,stock='',amount=''):
        '''
        调整数量
        '''           
        if stock[:3] in ['110','113','123','127','128','111'] or stock[:2] in ['11','12']:
            amount=math.floor(amount/10)*10
        else:
            amount=math.floor(amount/100)*100
        return amount
    def user_def_order_percent(self,
        name='西蒙斯测试',
        total=50000,
        trader_type='buy',
        stock='513100.SH',
        price=1.78,
        ratio=0.1):
        '''
        自定义组合总金额百分比调整函数
        '''
        volue=total*ratio
        amount=volue/price
        amount=self.adjust_amount(stock,amount)
        buy_value=amount*price
        if amount>=10:
            account=self.trader.balance()
            position=self.trader.position()
            if position.shape[0]>0:
                position=position[position['证券代码']==stock]
                if position.shape[0]>0:
                    hold_amount=position['股票余额'].tolist()[-1]
                    av_amount=position['可用余额'].tolist()[-1]
                else:
                    hold_amount=0
                    av_amount=0
            else:
                hold_amount=0
                av_amount=0
            av_cash=account['可用金额'].tolist()[-1]
            if trader_type=='B':
                if self.check_is_buy(stock=stock,amount=amount,price=price):
                    print('{}{} 组合资金{} 调整比例{} 买入 {} '.format(name,stock,total,ratio,amount))
                    return trader_type,amount
                else:
                    print('{} {} 买入不了{} 组合资金{} 调整比例{},可用金额{} 小于买入市值{}'.format(name,stock,amount,total,ratio,av_cash,buy_value))
                    return '',0
            elif  trader_type=='S':
                if self.check_is_sell(stock=stock,amount=amount):
                    print('{} {} 组合资金{} 调整比例{} 卖出{} '.format(name,stock,total,ratio,amount))
                    return trader_type,amount
                else:
                    print('{} {} 卖出不了,可用数量{} 小于卖出数量{}'.format(name,stock,av_amount,amount))
                    return '',0
            elif trader_type=='不变':
                print('{} 没有变化'.format(stock))
                return '',0
            else:
                print('{} 未知道的交易类型'.format(stock))
                return '',0
        else:
            print('{} 低于最低交易数量'.format(stock))
            return '',0
    def check_not_trader_data(self):
        '''
        检查单子是不是委托了
        包含了废单避免废单一直下
        '''
        with open('{}/策略配置.json'.format(self.path),'r+',encoding='utf-8') as f:
            com=f.read()
        text=json.loads(com)
        st_name=text['策略名称']
        trader_log=self.trader.today_entrusts()
        if trader_log.shape[0]>0:
            trader_log['策略']=trader_log['委托备注'].apply(lambda x: str(x)[:len(st_name)])
            trader_log=trader_log[trader_log['策略']==st_name]
            if trader_log.shape[0]>0:
                trader_log['委托备注']=trader_log['委托备注'].astype(str)
                maker_list=trader_log['委托备注'].tolist()
            else:
                maker_list=[]
        else:
            maker_list=[]
        return maker_list
   
    def get_buy_sell_data(self,total=50000,name='西蒙斯测试1',zh='ZH3368671'):
        '''
        获取买卖数据
        '''
        df=self.get_trader_adjust_data(name=name,zh=zh)
        if df.shape[0]>0:
            amount_list=[]
            position=self.trader.position()
            if position.shape[0]>0:
                position=position[position['股票余额']>=10]
                if position.shape[0]>0:
                    hold_stock_dict=dict(zip(position['证券代码'].tolist(),position['股票余额']))
                    av_stock_dict=dict(zip(position['证券代码'].tolist(),position['可用余额']))
                else:
                    hold_stock_dict={}
                    av_stock_dict={}
            else:
                hold_stock_dict={}
                av_stock_dict={}
            df['股票余额']=df['证券代码'].apply(lambda x :hold_stock_dict.get(x,0))
            df['可用余额']=df['证券代码'].apply(lambda x :av_stock_dict.get(x,0))
            for name,stock,trader_type,ratio,av_amount in zip(df['组合名称'],df['证券代码'],
                df['交易类型'],df['调整比例'],df['可用余额']):
                try:
                    ratio=abs(ratio/100)
                    price=self.get_price(stock)
                    trader_type,amount=self.user_def_order_percent(
                        name=name,
                        total=total,
                        trader_type=trader_type,
                        stock=stock,
                        price=price,
                        ratio=ratio)
                    
                    if trader_type=='B' and amount>=10:
                        amount_list.append(amount)
                    elif trader_type=='S' and amount>=10 and av_amount>=10:
                        if av_amount>=amount:
                            amount_list.append(amount)
                        else:
                            amount_list.append(av_amount)
                    else:
                        amount_list.append(0)
                except Exception as e:
                    print(e,stock,'分析有问题')
                    amount_list.append(0)
            df['交易数量']=amount_list
        else:
            df=pd.DataFrame()
        if df.shape[0]>0:
            maker_list=self.check_not_trader_data()
            df['成功委托']=df['投资备注'].apply(lambda x: '是' if x in maker_list else '不是')
            not_order=df[df['成功委托']=='不是']
            order=df[df['成功委托']=='是']
            net_trader=df[df['交易数量']==0]
            trader=not_order[not_order['交易数量']>=10]
            buy_df=trader[trader['交易类型']=='B']
            sell_df=trader[trader['交易类型']=='S']
            print('已经委托的数据*****')
            print(order)
            print('{}不能交易的股票等待下次成交交易数量为0'.format(name))
            print(net_trader)
            print('{} 买入股票************'.format(name))
            print(buy_df)
            print('{} 卖出股票数据***********'.format(name))
            print(sell_df)
        else:
            buy_df=pd.DataFrame()
            sell_df=pd.DataFrame()
        return buy_df,sell_df
    def seed_trader_data(self,msg='test'):
        '''
        发送交易信号
        '''
        with open('{}/策略配置.json'.format(self.path),'r+',encoding='utf-8') as f:
            com=f.read()
        text=json.loads(com)
        seed_type=text['通知发送方式']
        sender_email =text['发送QQ']
        receiver_email =text['接收QQ']
        password =text['QQ掩码']
        dd_token_list=text['钉钉token']
        wx_token_list=text['企业微信token']
        api=seed_trader_info(
            seed_type=seed_type,
            sender_email=sender_email,
            receiver_email=receiver_email,
            password=password,
            dd_token_list=dd_token_list,
            wx_token_list=wx_token_list
            )
        api.seed_trader_info(msg=msg)
    def run_tarder_func(self,total=50000,name='西蒙斯测试',zh='ZH3368671'):
        '''
        运行交易函数
        '''
        #if self.check_is_trader_date_1():
        if True:
            buy_df,sell_df=self.get_buy_sell_data(
                total=total,name=name,zh=zh)
            #先卖出在买入
            if sell_df.shape[0]>0:
                for stock,amount,maker in zip(sell_df['证券代码'],
                    sell_df['交易数量'],sell_df['投资备注']):
                    price=self.get_price(stock)
                    if self.check_is_sell(stock=stock,amount=amount):
                        self.trader.sell(
                            security=stock,
                            amount=amount,
                            price=price,
                            strategy_name=maker,
                            order_remark=maker)
                        print("{} 卖出{} 数量{} 价格{}".format(name,stock,amount,price))
                        msg="""
                        策略:索普量化雪球交易系统,
                        交易状态:成功,
                        交易类型:卖出,
                        时间:"{}",
                        证券代码:"{}",
                        数量:"{}",
                        价格:"{}",
                        """.format(datetime.now(),stock,amount,price)
                        self.seed_trader_data(msg=msg)
                    else:
                        print('{} 不能卖出{}'.format(name,stock))
            else:
                print('{} 没有卖出的数据'.format(name))
            #买入
            if buy_df.shape[0]>0:
                for stock,amount,maker in zip(buy_df['证券代码'],buy_df['交易数量'],buy_df['投资备注']):
                    price=self.get_price(stock)
                    if self.check_is_buy(stock=stock,amount=amount,price=price):
                        self.trader.buy(
                            security=stock,
                            amount=amount,
                            price=price,
                            strategy_name=maker,
                            order_remark=maker)
                        print("{} 买入{} 数量{} 价格{}".format(name,stock,amount,price))
                        msg="""
                        策略:索普量化雪球交易系统,
                        交易状态:成功,
                        交易类型:买入,
                        时间:"{}",
                        证券代码:"{}",
                        数量:"{}",
                        价格:"{}",
                        """.format(datetime.now(),stock,amount,price)
                        self.seed_trader_data(msg=msg)
                    else:
                        print('{} 不能买入{}'.format(name,stock))
            else:
                print('{} 没有买入的数据'.format(name))
        else:
            print(datetime.now(),'{}不是交易时间'.format(name))
    def get_updata_trader(self):
        '''
        更新多策略交易
        '''
        if self.check_is_trader_date_1():
            with open('{}/策略配置.json'.format(self.path),'r+',encoding='utf-8') as f:
                com=f.read()
            text=json.loads(com)
            name_list=text['组合名称']
            zh_list=text['组合代码']
            total_list=text['组合金额']
            ratio_list=text['组合比例']
            n=text['不同组合间隔时间']
            down_type=text['组合金额模式']
            account=self.trader.balance()
            total_cash=account['总资产'].tolist()[-1]
            for name,zh,total,ratio in zip(name_list,zh_list,total_list,ratio_list):
                try:
                    if down_type=='自定义':
                        total=total
                    elif down_type=='比例':
                        total=total_cash*ratio
                    else:
                        total=total_cash
                    print('*************策略:{} 下单模式:{}********************************'.format(name,down_type))
                    print('************************************************************************************************')
                    self.run_tarder_func(total=total,name=name,zh=zh)
                    time.sleep(n)
                except Exception as e:
                    print(e,name,'策略运行有问题*****************')
        else:
            print('{}交易系统目前不是交易时间'.format(datetime.now()))
    
    def check_is_trader_date_1(self):
        '''
        检测是不是交易时间
        '''
        with open('{}/分析配置.json'.format(self.path),'r+',encoding='utf-8') as f:
            com=f.read()
        text=json.loads(com)
        password=text['软件授权码']
        trader_time=text['交易时间段']
        start_date=text['交易开始时间']
        end_date=text['交易结束时间']
        start_mi=text['开始交易分钟']
        jhjj=text['是否参加集合竞价']
        stats=self.password.decode_trader_password()
        if stats==True:
            if jhjj=='是':
                jhjj_time=15
            else:
                jhjj_time=30
            loc=time.localtime()
            tm_hour=loc.tm_hour
            tm_min=loc.tm_min
            wo=loc.tm_wday
            if wo<=trader_time:
                if tm_hour>=start_date and tm_hour<=end_date:
                    if tm_hour==9 and tm_min<jhjj_time:
                        return False
                    elif tm_min>=start_mi:
                        return True
                    else:
                        return False
                else:
                    return False    
            else:
                print('周末')
                return False
        else:
            print('**************软件授权码不正确联系作者微信xms_quants1**************')
            return False
if __name__=='__main__':
    '''
    索普量化雪球交易系统
    '''
    with open('分析配置.json','r+',encoding='utf-8') as f:
        com=f.read()
    text=json.loads(com)
    trader_tool=text['交易系统']
    exe=text['同花顺下单路径']
    tesseract_cmd=text['识别软件安装位置']
    qmt_path=text['qmt路径']
    qmt_account=text['qmt账户']
    qmt_account_type=text['qmt账户类型']
    data_api=text['交易数据源']
    trader=joinquant_trader(
        trader_tool=trader_tool,
        exe=exe,
        tesseract_cmd=tesseract_cmd,
        qmt_path=qmt_path,
        qmt_account=qmt_account,
        qmt_account_type=qmt_account_type,
        data_api=data_api)
    trader.connact()
    trader.get_trader_adjust_data()
    schedule.every(0.05).minutes.do(trader.get_updata_trader)
    while True:
        schedule.run_pending()
        time.sleep(1)
    

回复

您需要登录后才可以回帖 登录 | 立即注册

客服专线

400-080-8112

用思考的速度交易,用真诚的态度合作,我们是认真的!
  • 关注公众号
  • 添加微信客服
Copyright © 2001-2025 迅投QMT社区 版权所有 All Rights Reserved. 京ICP备2025122616号-3
关灯 快速发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表