一、前言
构建一个完整的期货量化交易系统是每个量化交易者的目标。本文将详细介绍如何使用Python和天勤量化(TqSdk)从零开始构建一个功能完整的量化交易系统。
本文将介绍:
- 系统架构设计
- 数据管理模块
- 策略模块
- 风控模块
- 交易执行模块
- 监控与日志
二、为什么选择天勤量化(TqSdk)
TqSdk系统构建支持:
| 功能 | 说明 |
|---|---|
| 完整API | 提供完整的交易API |
| 数据接口 | 支持历史数据和实时数据 |
| 回测支持 | 内置回测框架 |
| 文档完善 | 详细的文档和示例 |
安装方法:
pipinstalltqsdk pandas numpy三、系统架构设计
3.1 系统模块
| 模块 | 功能 | 重要性 |
|---|---|---|
| 数据管理 | 数据获取、存储、处理 | ⭐⭐⭐⭐⭐ |
| 策略引擎 | 策略开发、执行 | ⭐⭐⭐⭐⭐ |
| 风控模块 | 风险控制、止损止盈 | ⭐⭐⭐⭐⭐ |
| 交易执行 | 订单管理、执行 | ⭐⭐⭐⭐⭐ |
| 监控日志 | 系统监控、日志记录 | ⭐⭐⭐⭐ |
3.2 系统流程
数据获取 → 策略计算 → 风控检查 → 交易执行 → 监控记录四、数据管理模块
4.1 数据获取类
#!/usr/bin/env python# -*- coding: utf-8 -*-""" 功能:数据管理模块 说明:本代码仅供学习参考 """fromtqsdkimportTqApi,TqAuthimportpandasaspdimportnumpyasnpimportsqlite3fromdatetimeimportdatetimeclassDataManager:"""数据管理类"""def__init__(self,api):self.api=api self.db_path="trading_data.db"self.init_database()definit_database(self):"""初始化数据库"""conn=sqlite3.connect(self.db_path)cursor=conn.cursor()# 创建K线数据表cursor.execute(''' CREATE TABLE IF NOT EXISTS klines ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT, datetime TEXT, open REAL, high REAL, low REAL, close REAL, volume INTEGER, open_oi INTEGER ) ''')conn.commit()conn.close()defget_klines(self,symbol,duration_seconds=3600,count=500):"""获取K线数据"""klines=self.api.get_kline_serial(symbol,duration_seconds,count)self.api.wait_update()returnklinesdefsave_klines(self,symbol,klines):"""保存K线数据"""conn=sqlite3.connect(self.db_path)cursor=conn.cursor()foridx,rowinklines.iterrows():cursor.execute(''' INSERT OR REPLACE INTO klines (symbol, datetime, open, high, low, close, volume, open_oi) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''',(symbol,str(idx),row['open'],row['high'],row['low'],row['close'],row['volume'],row['open_oi']))conn.commit()conn.close()defload_klines(self,symbol,start_date=None,end_date=None):"""从数据库加载K线数据"""conn=sqlite3.connect(self.db_path)query="SELECT * FROM klines WHERE symbol = ?"params=[symbol]ifstart_date:query+=" AND datetime >= ?"params.append(start_date)ifend_date:query+=" AND datetime <= ?"params.append(end_date)df=pd.read_sql_query(query,conn,params=params)conn.close()ifnotdf.empty:df['datetime']=pd.to_datetime(df['datetime'])df.set_index('datetime',inplace=True)returndf# 使用示例api=TqApi(auth=TqAuth("快期账户","快期密码"))data_manager=DataManager(api)klines=data_manager.get_klines("SHFE.rb2510")data_manager.save_klines("SHFE.rb2510",klines)api.close()五、策略模块
5.1 策略基类
fromabcimportABC,abstractmethodclassBaseStrategy(ABC):"""策略基类"""def__init__(self,api,symbol):self.api=api self.symbol=symbol self.klines=None@abstractmethoddefon_bar(self,klines):"""K线更新回调"""pass@abstractmethoddefgenerate_signal(self):"""生成交易信号"""passdefupdate_klines(self):"""更新K线数据"""ifself.klinesisNone:self.klines=self.api.get_kline_serial(self.symbol,3600,200)else:self.api.wait_update()returnself.klines5.2 具体策略实现
fromtqsdk.tafuncimportmaclassMovingAverageStrategy(BaseStrategy):"""移动平均策略"""def__init__(self,api,symbol,fast_period=5,slow_period=20):super().__init__(api,symbol)self.fast_period=fast_period self.slow_period=slow_perioddefgenerate_signal(self):"""生成交易信号"""klines=self.update_klines()ma_fast=ma(klines['close'],self.fast_period)ma_slow=ma(klines['close'],self.slow_period)ifma_fast.iloc[-1]>ma_slow.iloc[-1]andma_fast.iloc[-2]<=ma_slow.iloc[-2]:return1# 买入elifma_fast.iloc[-1]<ma_slow.iloc[-1]andma_fast.iloc[-2]>=ma_slow.iloc[-2]:return-1# 卖出return0# 持有六、风控模块
6.1 风控类
classRiskManager:"""风险管理类"""def__init__(self,api,max_position=10,max_loss_per_trade=0.02,max_daily_loss=0.05):self.api=api self.max_position=max_position self.max_loss_per_trade=max_loss_per_trade self.max_daily_loss=max_daily_loss self.daily_pnl=0defcheck_position_limit(self,current_position,new_position):"""检查仓位限制"""ifabs(new_position)>self.max_position:returnFalse,f"仓位超过限制:{self.max_position}"returnTrue,"通过"defcheck_loss_limit(self,entry_price,current_price,position):"""检查亏损限制"""ifposition==0:returnTrue,"通过"pnl_ratio=abs(current_price-entry_price)/entry_priceifpnl_ratio>self.max_loss_per_trade:returnFalse,f"单笔亏损超过限制:{self.max_loss_per_trade:.2%}"returnTrue,"通过"defcheck_daily_loss(self,daily_pnl,account_balance):"""检查日亏损限制"""loss_ratio=abs(daily_pnl)/account_balanceifdaily_pnl<0else0ifloss_ratio>self.max_daily_loss:returnFalse,f"日亏损超过限制:{self.max_daily_loss:.2%}"returnTrue,"通过"defcalculate_position_size(self,account_balance,risk_per_trade=0.01):"""计算仓位大小"""risk_amount=account_balance*risk_per_trade# 简化处理,实际需要根据止损距离计算position_size=int(risk_amount/100)# 假设每手风险100元returnposition_size七、交易执行模块
7.1 交易执行类
classOrderManager:"""订单管理类"""def__init__(self,api,symbol):self.api=api self.symbol=symbol self.positions={}self.orders={}defget_position(self):"""获取当前持仓"""position=self.api.get_position(self.symbol)self.api.wait_update()returnpositiondefplace_order(self,direction,offset,volume,price=None):"""下单"""ifprice:order=self.api.insert_order(self.symbol,direction,offset,volume,limit_price=price)else:order=self.api.insert_order(self.symbol,direction,offset,volume)self.api.wait_update()returnorderdefcancel_order(self,order_id):"""撤单"""self.api.cancel_order(order_id)self.api.wait_update()defexecute_signal(self,signal,current_position,target_position):"""执行交易信号"""ifsignal==0:returnNonevolume=abs(target_position-current_position)ifvolume==0:returnNoneiftarget_position>current_position:direction="BUY"else:direction="SELL"offset="OPEN"iftarget_position!=0else"CLOSE"order=self.place_order(direction,offset,volume)returnorder八、监控与日志
8.1 日志类
importloggingfromdatetimeimportdatetimeclassTradingLogger:"""交易日志类"""def__init__(self,log_file="trading.log"):logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler(log_file,encoding='utf-8'),logging.StreamHandler()])self.logger=logging.getLogger(__name__)deflog_signal(self,symbol,signal,price):"""记录信号"""self.logger.info(f"信号 -{symbol}:{signal}, 价格:{price}")deflog_order(self,order_id,symbol,direction,volume,price):"""记录订单"""self.logger.info(f"订单 -{order_id}:{symbol}{direction}{volume}@{price}")deflog_error(self,error_msg):"""记录错误"""self.logger.error(f"错误:{error_msg}")deflog_pnl(self,symbol,pnl):"""记录盈亏"""self.logger.info(f"盈亏 -{symbol}:{pnl:.2f}")# 使用示例logger=TradingLogger()logger.log_signal("SHFE.rb2510",1,4000)九、完整系统整合
9.1 交易系统类
classTradingSystem:"""完整交易系统"""def__init__(self,api,symbol,strategy,risk_manager):self.api=api self.symbol=symbol self.strategy=strategy self.risk_manager=risk_manager self.order_manager=OrderManager(api,symbol)self.logger=TradingLogger()self.running=Falsedefstart(self):"""启动系统"""self.running=Trueself.logger.logger.info("交易系统启动")whileself.running:try:# 获取信号signal=self.strategy.generate_signal()# 获取当前持仓position=self.order_manager.get_position()current_position=position.pos_long-position.pos_short# 风控检查account=self.api.get_account()self.api.wait_update()# 计算目标仓位ifsignal!=0:position_size=self.risk_manager.calculate_position_size(account.balance)target_position=position_sizeifsignal>0else-position_sizeelse:target_position=0# 检查仓位限制check_result,msg=self.risk_manager.check_position_limit(current_position,target_position)ifnotcheck_result:self.logger.log_error(msg)continue# 执行交易iftarget_position!=current_position:quote=self.api.get_quote(self.symbol)self.api.wait_update()order=self.order_manager.execute_signal(signal,current_position,target_position)iforder:self.logger.log_order(order.order_id,self.symbol,order.direction,order.volume,quote.last_price)# 等待更新self.api.wait_update()time.sleep(1)exceptExceptionase:self.logger.log_error(str(e))time.sleep(5)defstop(self):"""停止系统"""self.running=Falseself.logger.logger.info("交易系统停止")# 使用示例api=TqApi(auth=TqAuth("快期账户","快期密码"))strategy=MovingAverageStrategy(api,"SHFE.rb2510")risk_manager=RiskManager(api)system=TradingSystem(api,"SHFE.rb2510",strategy,risk_manager)try:system.start()exceptKeyboardInterrupt:system.stop()finally:api.close()十、总结
10.1 系统构建要点
| 要点 | 说明 |
|---|---|
| 模块化设计 | 各模块独立,便于维护 |
| 错误处理 | 完善的错误处理机制 |
| 日志记录 | 详细记录系统运行情况 |
| 风控优先 | 风控是系统核心 |
10.2 注意事项
- 模块化- 保持模块独立
- 错误处理- 完善的异常处理
- 日志记录- 详细记录运行情况
- 测试验证- 充分测试后再实盘
免责声明:本文仅供学习交流使用,不构成任何投资建议。期货交易有风险,入市需谨慎。
更多资源:
- 天勤量化官网:https://www.shinnytech.com
- GitHub开源地址:https://github.com/shinnytech/tqsdk-python
- 官方文档:https://doc.shinnytech.com/tqsdk/latest