1 本篇教程默认阅读者已经知晓 python 的基本语法,如变量类型,循环,条件判断
2.本篇教程编写的目的是为了帮助量化小白快速上手 xtquant,并搭建自己的量化交易系统
3.作者本人并不是程序员出身,如在内容上有错误/纰漏,也欢迎各位给我进行留言或者私信都可以
0.安装 python 与 xtquant 包
【代码】获取高级行情数据,并通过 qmt 进行实际下单交易,自动实现止盈止损管理
标的池选择:上证 50
买入条件:当股票 1h 周期出现 ma 金叉,且 1d 周期出现 macd 位于 0 轴之上的情况,触发买入条件
卖出条件:当持仓的股票盈利超过设定幅度,或亏损超过设定幅度时,触发卖出条件
# 股票池:50etf标的池
# 策略:双均线策略
# 止盈止损:比例止盈止损
import pandas as pd
import numpy as np
import time
import datetime
from xtquant import xtdata,xttrader,xtconstant
from xtquant.xttype import StockAccount
## 策略所用的指标
def ema(df:pd.DataFrame,N):
return df.ewm(span=N, adjust=False).mean()
def MACD(close:pd.DataFrame, short = 12, long = 26, M = 9):
DIF = ema(close,short) - ema(close,long)
DEA = ema(DIF,M)
return DIF.round(3), DEA.round(3)
def CROSSUP(a, b):
"""
向上穿越: 表当a从下方向上穿过b, 成立返回1, 否则返回0
Args:
a (pandas.Series): 数据序列1
b (pandas.Series): 数据序列2
Returns:
pandas.Series: 上穿标志序列
"""
crossup_data = pd.Series(np.where((a > b) & (a.shift(1) <= b.shift(1)), 1, 0))
return crossup_data
# 初始化部分
### 这块有很多可以自己优化的点,比如一些固定的东西可以直接写成配置文件,自己再把整个初始化的部分封装成一个函数,避免重复写
xtdata.connect(port=58601) # 连接主程序开放的数据端口,以获取历史数据和实时数据
account = StockAccount("55001435","STOCK") # 设置交易账户,这个账户必须在你界面的能看到,且能手动下单的
xt_trade = xttrader.XtQuantTrader(r"C:\Program Files\国金证券QMT交易端\userdata_mini",int(time.time())) # 连接miniqmt,如果是连接投研的话,目录是..\userdata
class Mycallback(xttrader.XtQuantTraderCallback): # 继承XtQuantTraderCallback类,覆盖定义自己的回调函数,这个类是开源的,不懂的可以点进去自己看
# 这个策略其实用不上回调,这里只写一个演示用法
def on_stock_order(self, order):
"""
委托回报推送
:param order: XtOrder对象
:return:
"""
print(datetime.datetime.now(), '委托回调', order.order_remark)
def on_stock_trade(self, trade):
"""
成交变动推送
:param trade: XtTrade对象
:return:
"""
print(datetime.datetime.now(), '成交回调', trade.order_remark)
callback = Mycallback()
xt_trade.register_callback(callback) # 注册回调信息
xt_trade.start() # 启动交易线程
connect_result = xt_trade.connect() # 连接账户准备交易
subscribe_result = xt_trade.subscribe(account) # 订阅接受账户的回调信息,没这一步的话收不到
if connect_result != 0:
raise KeyboardInterrupt("连接交易失败,请查看https://dict.thinktrader.net/nativeApi/question_function.html?id=7zqjlm按步骤进行排查")
# 设置参数
strategyName = "双均线_MACD_大小周期共振策略" # 设置策略名称
stock_list = xtdata.get_stock_list_in_sector("上证50") # 设置股票交易列表
period1 = "1d" # 大数据周期
period2 = "1h" # 小数据周期
line_1 = 10 # 短周期
line_2 = 20 # 长周期
macd_n1,macd_n2,macd_M = 12, 26, 9 # MACD指标参数
take_profit_ratio = 10 # 止盈比例,单位%
stop_loss_ratio = 5 # 止损比例,单位%
# 初始化持仓容器
holdings = {}
# 信号计算
def strategyFunc(data):
# 获取行情数据
kline_1d:pd.DataFrame = xtdata.get_market_data_ex([],stock_list,period=period1,count=40)
kline_1h:pd.DataFrame = xtdata.get_market_data_ex([],stock_list,period=period2,count=300)
# 获取账户持仓数据
for obj in xt_trade.query_stock_positions(account):
stock_code = obj.stock_code
if stock_code not in stock_list:
continue
holdings[stock_code] = {
"volume":obj.volume, # 持仓量
"can_use_volume":obj.volume, # 可用量
"open_price":obj.open_price, # 持仓均价
"market_value":obj.market_value # 市值
}
print(holdings)
tick = xtdata.get_full_tick(list(holdings.keys()) + stock_list)
# print(data)
for stock in stock_list:
data1 = kline_1h[stock] # 取这个标的的1h数据
data2 = kline_1d[stock] # 取这个标的的1d数据
## 计算均线
ma1 = data1["close"].rolling(line_1).mean() # 计算短周期均线
ma2 = data1["close"].rolling(line_2).mean() # 计算长周期均线
signal = CROSSUP(ma1,ma2) # 计算金叉信号序列
## 计算MACD
dif,dea = MACD(data2["close"])
diff = dif - dea
# print(signal,diff)
# 如果MACD是金叉状态,即DIFF在0轴之上,且1小时均线金叉,则触发买入信号
# print(stock,signal.iloc[-1] , diff.iloc[-1])
if signal.iloc[-1] and diff.iloc[-1] > 0:
# 判断是否有持仓,已经有持仓就不开仓了
if stock in holdings:
continue
else:
# 按最新价买入标的1手,实际交易中还要考虑买入但未成交的情况下,怎么防止超单
xt_trade.order_stock_async(account, stock, xtconstant.STOCK_BUY, 100, xtconstant.LATEST_PRICE, 0, strategyName, 'order_test')
# 止盈止损部分
for stock in holdings:
_d = holdings[stock]
cost = _d["open_price"] * _d["volume"] # 计算成本
profit = _d["market_value"] - cost # 计算盈利金额
# 如果亏损超过了设定的幅度
if (cost / _d["market_value"] - 1) * 100 < - stop_loss_ratio and _d["volume"] > 0:
# 卖出所有持仓
xt_trade.order_stock_async(account, stock, xtconstant.STOCK_SELL, _d["volume"], xtconstant.LATEST_PRICE, 0, strategyName, 'stop_loss_ratio')
# 如果盈利超过了指定的幅度
if (cost / _d["market_value"] - 1) * 100 > take_profit_ratio and _d["volume"] > 0:
# 卖出所有持仓
xt_trade.order_stock_async(account, stock, xtconstant.STOCK_SELL, _d["volume"], xtconstant.LATEST_PRICE, 0, strategyName, 'take_profit_ratio')
# 行情数据订阅
for i in stock_list:
xtdata.subscribe_quote(i,period=period1,count=-1)
xtdata.subscribe_quote(i,period=period2,count=-1)
xtdata.subscribe_quote("000300.SH",period="tick",callback=strategyFunc) # 订阅主图tick,并用主图tick来驱动策略信号计算,来实现类似与内置python中handlebar的机制
xtdata.run()