你的位置:炒股配资网址_实盘配资门户网_股票配资网平台 > 股票配资网平台 > 推荐股票配资 15天搭建ETF量化交易系统Day11—miniQMT自动交易真香!
推荐股票配资 15天搭建ETF量化交易系统Day11—miniQMT自动交易真香!
发布日期:2025-01-22 14:37    点击次数:168

推荐股票配资 搭建过程

每个交易者都应该形成一套自己的交易系统。

很多交易者也清楚知道,搭建自己交易系统的重要性。现实中,从0到1往往是最难跨越的一步。

授人鱼不如授人以渔,为了帮助大家跨出搭建量化系统的第一步,我们决定推出这个主题系列。

这个系列中,我们用Python从0开始一步步搭建出一套ETF量化交易系统(选择ETF标的是因为对于普通交易者来说,ETF相对于选强势股难度要小,而且没有退市风险)。大家可以跟随着我们的实现路径来一起学习,从过程中掌握方法。

掌握了方法之后,你可以换成期货系统、比特币系统、美股系统,然后在实战中不断去完善自己的系统了。

搭建一套ETF量化交易系统涉及多个模块和组件的协同工作,包括数据源模块、量化策略模块、可视化模块、数据库模块、回测评估模块、自动交易模块等等。

DAY1链接如下:15天搭建ETF量化交易系统Day1—数据源模块

DAY2链接如下:15天搭建ETF量化交易系统Day2—图形显示模块

DAY3链接如下:15天搭建ETF量化交易系统Day3—上手经典回测框架

DAY4链接如下:15天搭建ETF量化交易系统Day4—玩转海龟交易策略

DAY5链接如下:15天搭建ETF量化交易系统Day5—打造实盘量化机器人

DAY6链接如下:15天搭建ETF量化交易系统Day6—打通同花顺自动交易

DAY7链接如下:15天搭建ETF量化交易系统Day7—全自动化交易系统

DAY8链接如下:15天搭建ETF量化交易系统Day8—强化自动交易模块

DAY9链接如下:15天搭建ETF量化交易系统Day9—玩大A必学网格策略

DAY10链接如下:15天搭建ETF量化交易系统Day10—借用网格思想做仓位管理

之前DAY6我们已经打通自动交易环节,采用的方案是使用easytrader库搭建本地自动交易环境,然后用程序自动操作同花顺交易客户端下单。

不过这个属于曲线救国的方案,长期运行并不稳定。在大家的强烈推荐下,我们决定使用正规的量化交易平台作为下单的最后环节——QMT!

接口介绍
QMT(Quantitative Market Trading)是迅投公司开发的量化交易软件,专供券商采购,现在个人投资者也可申请使用。

MiniQMT 是 QMT 的简化版,执行完安装过程这两个就都有了。

MiniQMT的好处是我们可以用自己的量化系统框架,直接向券商发送下单信息。

MiniQMT 提供了一个 XtQuant 的 Python 库,可以 import 它并调用它的方法下单。

XtQuant 目前不能通过 pip 安装,可以下载后放在Python第三方库目录下。

MiniQMT 的下单信息流向如下。

图片

在Python实盘代码中import xtquant,通过xtquant库提供的方法下单(提前打开miniQMT),miniQMT 的桌面应用接收到xtquant库发出的下单请求,miniQMT 将下单信息发送给券商的交易服务器。

图片

功能实现

接下来,我们用miniQMT接口来代替之前easytrader实现的接口,并且把交易的功能封装成一个类,以供系统整体的调用。

类名为QmtTrader,其中包括了“连接客户端”、“获取资金状况”、“获取当前仓位”、“查询当日成交”、“买入”、“卖出”等方法。

class QmtTrader: def __init__(self,path= r'C:\国金QMT交易端\userdata_mini', account='xxxxxx', account_type='STOCK', is_slippage=True, slippage=0.01) -> None: ''' 简化版的qmt_trder方便大家做策略的开发类的继承 ''' self.xt_trader='' self.acc='' self.path=path self.session_id=int(self.random_session_id()) self.account=account self.account_type=account_type if is_slippage==True: self.slippage=slippage else: self.slippage=0 def random_session_id(self): ''' 随机id ''' session_id='' for i in range(0,9): session_id+=str(random.randint(1,9)) return session_id def connect(self): ''' 连接 path qmt userdata_min是路径 session_id 账户的标志,随便 account账户, account_type账户内类型 ''' print('开始链接QMT...') # path为mini qmt客户端安装目录下userdata_mini路径 path = self.path # session_id为会话编号,策略使用方对于不同的Python策略需要使用不同的会话编号 session_id = self.session_id xt_trader = XtQuantTrader(path, session_id) # 创建资金账号为1000000365的证券账号对象 account=self.account account_type=self.account_type acc = StockAccount(account_id=account, account_type=account_type) # 启动交易线程 xt_trader.start() # 建立交易连接,返回0表示连接成功 connect_result = xt_trader.connect() if connect_result==0: self.xt_trader=xt_trader self.acc=acc print('QMT连接成功!') else: print('QMT连接失败!') def get_position(self): ''' 查询账户所有的持仓 ''' positions = self.xt_trader.query_stock_positions(self.acc) print('持仓数量:', len(positions)) data=pd.DataFrame() if len(positions) != 0: for i in range(len(positions)): df=pd.DataFrame() df['账号类型']=[positions[i].account_type] df['资金账号']=[positions[i].account_id] df['证券代码']=[positions[i].stock_code] df['证券代码']=df['证券代码'].apply(lambda x:str(x)[:6]) df['持仓数量']=[positions[i].volume] df['可用数量']=[positions[i].can_use_volume] df['平均建仓成本']=[positions[i].open_price] df['市值']=[positions[i].market_value] data=pd.concat([data,df],ignore_index=True) return data else: print('没有持股') df=pd.DataFrame() df['账号类型']=[None] df['资金账号']=[None] df['证券代码']=[None] df['持仓数量']=[None] df['可用数量']=[None] df['平均建仓成本']=[None] df['市值']=[None] return df def get_balance(self): ''' 返回当前证券账号的资产数据 ''' asset = self.xt_trader.query_stock_asset(account=self.acc) data_dict={} if asset: data_dict['账号类型']=asset.account_type data_dict['资金账户']=asset.account_id data_dict['可用金额']=asset.cash data_dict['冻结金额']=asset.frozen_cash data_dict['持仓市值']=asset.market_value data_dict['总资产']=asset.total_asset return data_dict else: print('获取失败资金') data_dict['账号类型']=[None] data_dict['资金账户']=[None] data_dict['可用金额']=[None] data_dict['冻结金额']=[None] data_dict['持仓市值']=[None] data_dict['总资产']=[None] return data_dict def today_trades(self): ''' 当日成交 ''' trades = self.xt_trader.query_stock_trades(self.acc) print('成交数量:', len(trades)) data=pd.DataFrame() if len(trades) != 0: for i in range(len(trades)): df=pd.DataFrame() df['账号类型']=[trades[i].account_type] df['资金账号']=[trades[i].account_id] df['证券代码']=[trades[i].stock_code] df['证券代码']=df['证券代码'].apply(lambda x:str(x)[:6]) df['委托类型']=[trades[i].order_type] df['成交编号']=[trades[i].traded_id] df['成交时间']=[trades[i].traded_time] df['成交均价']=[trades[i].traded_price] df['成交数量']=[trades[i].traded_volume] df['成交金额']=[trades[i].traded_amount] df['订单编号']=[trades[i].order_id] df['柜台合同编号']=[trades[i].order_sysid] df['策略名称']=[trades[i].strategy_name] df['委托备注']=[trades[i].order_remark] data=pd.concat([data,df],ignore_index=True) data['成交时间']=pd.to_datetime(data['成交时间'],unit='s') return data def today_entrusts(self): ''' 当日委托 :param account: 证券账号 :param cancelable_only: 仅查询可撤委托 :return: 返回当日所有委托的委托对象组成的list ''' orders = self.xt_trader.query_stock_orders(self.acc) print('委托数量', len(orders)) data=pd.DataFrame() if len(orders) != 0: for i in range(len(orders)): df=pd.DataFrame() df['账号类型']=[orders[i].account_type] df['资金账号']=[orders[i].account_id] df['证券代码']=[orders[i].stock_code] df['证券代码']=df['证券代码'].apply(lambda x:str(x)[:6]) df['订单编号']=[orders[i].order_id] df['柜台合同编号']=[orders[i].order_sysid] df['报单时间']=[orders[i].order_time] df['委托类型']=[orders[i].order_type] df['委托数量']=[orders[i].order_volume] df['报价类型']=[orders[i].price_type] df['委托价格']=[orders[i].price] df['成交数量']=[orders[i].traded_volume] df['成交均价']=[orders[i].traded_price] df['委托状态']=[orders[i].order_status] df['委托状态描述']=[orders[i].status_msg] df['策略名称']=[orders[i].strategy_name] df['委托备注']=[orders[i].order_remark] data=pd.concat([data,df],ignore_index=True) data['报单时间']=pd.to_datetime(data['报单时间'],unit='s') return data else: print('目前没有委托') return data def check_stock_is_av_buy(self, stock='600031', price=17.70, amount=10, hold_limit=100000): ''' 检查是否可以买入 ''' hold_stock=self.get_position() try: del hold_stock['Unnamed: 0'] except: pass account=self.get_balance() try: del account['Unnamed: 0'] except: pass #买入是价值 value=priceamount cash=account['可用金额'] frozen_cash=account['冻结金额'] market_value=account['持仓市值'] total_asset=account['总资产'] if cash>=value: print('允许买入{} 可用现金{}大于买入金额{} 价格{} 数量{}'.format(stock,cash,value,price,amount)) return True else: print('不允许买入{} 可用现金{}小于买入金额{} 价格{} 数量{}'.format(stock,cash,value,price,amount)) return False def check_stock_is_av_sell(self, stock='600031', amount=10): ''' 检查是否可以卖出 ''' hold_data=self.get_position() try: del hold_data['Unnamed: 0'] except: pass account=self.get_balance() try: del account['Unnamed: 0'] except: pass cash=account['可用金额'] frozen_cash=account['冻结金额'] market_value=account['持仓市值'] total_asset=account['总资产'] stock_list=hold_data['证券代码'].tolist() if stock in stock_list: hold_num=hold_data[hold_data['证券代码']==stock]['可用余额'] if hold_num>=amount: print('允许卖出:{} 持股{} 卖出{}'.format(stock,hold_num,amount)) return True else: print('不允许卖出持股不足:{} 持股{} 卖出{}'.format(stock,hold_num,amount)) return False else: print('不允许卖出没有持股:{} 持股{} 卖出{}'.format(stock,0,amount)) return False def make_buy(self, security='600031.SH', amount=100, price=20, strategy_name='', order_remark=''): ''' 单独独立股票买入函数 ''' order_type=xtconstant.STOCK_BUY if price == 0: price_type=xtconstant.LATEST_PRICE else: price_type=xtconstant.FIX_PRICE order_volume=amount # 使用指定价下单,接口返回订单编号,后续可以用于撤单操作以及查询委托状态 if order_volume>0: fix_result_order_id = self.xt_trader.order_stock(account=self.acc,stock_code=security, order_type=order_type, order_volume=order_volume, price_type=price_type, price=price, strategy_name=strategy_name, order_remark=order_remark) print('交易类型{} 代码{} 价格{} 数量{} 订单编号{}'.format(order_type, security, price,order_volume,fix_result_order_id)) return fix_result_order_id else: print('买入 标的{} 价格{} 委托数量{}小于0有问题'.format(security, price, order_volume)) def make_sell(self,security='600031.SH', amount=100, price=20, strategy_name='', order_remark=''): ''' 单独独立股票卖出函数 ''' order_type=xtconstant.STOCK_SELL if price == 0: price_type=xtconstant.LATEST_PRICE else: price_type=xtconstant.FIX_PRICE order_volume=amount # 使用指定价下单,接口返回订单编号,后续可以用于撤单操作以及查询委托状态 if order_volume>0: fix_result_order_id = self.xt_trader.order_stock(account=self.acc,stock_code=security, order_type=order_type, order_volume=order_volume, price_type=price_type, price=price, strategy_name=strategy_name, order_remark=order_remark) print('交易类型{} 代码{} 价格{} 数量{} 订单编号{}'.format(order_type,security,price,order_volume,fix_result_order_id)) return fix_result_order_id else:            print('卖出 标的{} 价格{} 委托数量{}小于0有问题'.format(stock_code,price,order_volume))替换接口

接下来,我们在”Day7—全自动化交易系统“基础上替换新的交易接口。

比如“量化机器人”监测到有ETF符合买入条件时,查询交易账户是否有足够的资金能买入。当账户余额充足时,则立即以当前价格买入。

if self.qmt.check_stock_is_av_buy(code, df_index_data['close'][-1], 1000, 5000) == True:  self.qmt.make_buy(code, df_index_data['close'][-1], 1000)

比如“量化机器人”监测到有ETF符合卖出条件时,查询交易账户是否有仓位要卖出。当账户有持有的仓位时,则立即以当前价格卖出。

if self.qmt.check_stock_is_av_sell(code, 100) == True: self.qmt.make_sell(code, df_index_data['close'][-1], 2000)总结

实现了自动下单这个环节之后,接下去我们可以安心地研究策略,打造真正意义上闭环的量化交易系统,全自动化交易。

如何获取QMT安装包和开户可以看这篇介绍:量化交易自动下单方案—对接QMT已出炉说明

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报。