策略示例(python)
入门策略
buySellSymbol-股票买卖策略
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from xquant import *
'''
股票策略:买卖策略
本策略是一个简单的买卖策略,主要是体现如何下单的。当没有持仓时就进行买入操作,当有持仓时,就进行卖出平仓操作
回测标的:平安银行(000001.SZ)
'''
if __name__ == '__main__':
config = {
"user": "SDK-User", # 点击客户端管理平台右上角用户名可查看填写
"token": "SDK-Token", # 点击客户端管理平台右上角用户名可查看填写
"instance_id": "ID", # 客户端管理平台回测记录中本策略的回测ID,点击复制ID,粘贴此处即可
"login_endpoint": "https -h prx-01.upoem1.com -p 443", # 登录地址
"initialize": {
# symbols里设置单个股票或者其他有效的标的
"symbols": ["000001.SZ"],
# 必填:设置所需k线类型,interval可以选取1分钟,5分钟,15分钟,30分钟,60分钟,日k,count为提前缓存的数目
'bars': [
{
'interval': '1day',
'count': 60,
'match':True
}
],
# 必填: 设置回测开始和结束日期 市场初始资金
"backtest": {
"start_date": 20210101,
"end_date": 20221101,
"cash": {'CS': 1000000},
},
# 选填:为group_only,则只响应on_handle_data;为single_only,则只响应on_bar;为both,则两个回调同时响应
'mode': 'single_only',
# 必填: 设置交易手续费
"commission": 0.0003,
}
}
xquant.run_quant(config)
# 必要:每个交易日回测/模拟/实盘前要做的操作
def on_before_market_open(api, date_now):
# 必要:获取当个交易日需关注的股票
# 设置今天关注的股票,如果股票池中只有一只股票,则全部关注即可;股票池中股票过多时,需要先选股在设置部分关注以提高运行效率
api.set_focus_symbols(api.get_symbol_pool())
# 必要:每天回测/交易 策略 两种方式回调 on_bar/on_handle_data
# 用日K做回测,所以每天只会进入一次,收盘时响应此函数
# 策略逻辑:第一天买入,第二天卖出;判断逻辑,如果当前有仓位,则平仓,如果当前没有仓位,则买入
def on_bar(api, bar):
symbol_positions = api.get_symbol_positions() # 获取持仓标的信息
if symbol_positions: # 如果持仓数大于0
# 平仓
log.info("target position zero!")
api.target_position(symbol=bar.symbol, qty=0,price = float(bar.close)) # 卖出 symbol = 选中标的,数量变为0
else:
# 限价下单
log.info("target position 1000!")
api.target_position(symbol=bar.symbol, qty=1000,price = float(bar.close)) # 买入 symbol = 选中标的,直至持仓数达1000股
buySellFutures-期货买卖策略
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
期货策略:买卖策略
本策略是一个简单的期货买卖策略,主要是体现期货简单买卖
'''
from xquant import *
if __name__ == '__main__':
config = {
"user": "SDK-User", # 点击客户端管理平台右上角用户名可查看填写
"token": "SDK-Token", # 点击客户端管理平台右上角用户名可查看填写
"instance_id": "ID", # 客户端管理平台回测记录中本策略的回测ID,点击复制ID,粘贴此处即可
"login_endpoint": "https -h prx-01.upoem1.com -p 443", # 登录地址
# 初始化参数
"initialize": {
# symbol_sets里设置标的集合,如此处的IF.PRD指的就是IF品种的所有标准合约,不包含IFZ0.CFE和IFZ1.CFE
'symbols': ['IFZ0.CFE'],
'symbol_sets': ['IF.PRD'],
# 设置所需k线类型,interval可以选取1分钟,5分钟,15分钟,30分钟,60分钟,日k,count为提前缓存的数目
'bars': [
{
'interval': "1day",
'count': 100,
'match':True
}
],
# 必填: 设置回测开始和结束日期 市场初始资金
"backtest": {
"start_date": 20200101,
"end_date": 20221101,
"cash": {'CF': 1000000},
},
# 选填:为group_only,则只响应on_handle_data;为single_only,则只响应on_bar;为both,则两个回调同时响应
'mode': 'group_only',
# 必填: 设置交易手续费
"commission": 0.0003
}
}
xquant.run_quant(config)
def on_before_market_open(api, date_now):
api.futures_code = api.get_continuous_symbol("IFZ0.CFE") # 获得当前交易日IF主力合约代码
api.set_focus_symbols(api.futures_code)
def on_handle_data(api, time_now):
print(time_now)
symbol_positions = api.get_symbol_positions() # 获取持仓标的信息
bars = api.get_bars_history(symbol=api.futures_code, timespan="1day", count=1) # 获得合约当前bar数据
factor = bars['pre_close'] / bars['open'] # 当昨日收盘价与前开盘价之比
if symbol_positions: # 如果有持仓
if api.futures_code == symbol_positions[0].symbol: # 当前持仓为主力合约
# 止盈0.3%止损0.5%
if symbol_positions[0].pos_high / symbol_positions[0].pos_price > 1.03 \
or symbol_positions[0].pos_low / symbol_positions[0].pos_price < 0.95:
# 平仓
print("target position 0!") # 录入日志
api.target_position(symbol=symbol_positions[0].symbol, qty=0, price = symbol_positions[0].pos_high,side='short') # 卖出 ,symbol = 持仓标的,数量变为0
# 当前持仓非主力合约 则换仓为主力合约
else:
print("换合约", api.futures_code)
p_bars = api.get_bars_history(symbol=symbol_positions[0].symbol, timespan="1day", count=1) # 获得合约当前bar数据
api.target_position(symbol=symbol_positions[0].symbol, qty=0, price = float(p_bars['close']),side='short')
api.target_position(symbol=api.futures_code, qty=2, price = float(bars['close']) ,side='short')
else:
if factor[0] < 1:
print("target position 2") # 非必要: 输出日志
api.target_position(symbol=api.futures_code, qty=2, price = float(bars['close']), side='short') # 买入 symbol = 选中标的开空,直至持仓数达2手
进阶策略
net_trade-网格交易(期货)
本策略为经典的期货日内策略(网格交易),设置不同的临界线,并分配不同的资金仓位
# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals, division
from xquant import *
import numpy as np
import pandas as pd
'''
策略基本思想:本策略为经典的期货日内策略(网格交易),设置不同的临界线,并分配不同的资金仓位。
策略交易频率:1分钟
交易或订阅标的:rb1801
回测时间:2018-12-01 到2018-12-30
'''
if __name__ == '__main__':
config = {
"user": "SDK-User", # 点击客户端管理平台右上角用户名可查看填写
"token": "SDK-Token", # 点击客户端管理平台右上角用户名可查看填写
"instance_id": "ID", # 客户端管理平台回测记录中本策略的回测ID,点击复制ID,粘贴此处即可
"login_endpoint": "https -h prx-01.upoem1.com -p 443", # 登录地址
"loglevel": 'DEBUG',
"initialize": {
# symbols里设置单个股票或者其他有效的标的
'symbols': ['IFZ0.CFE'],
'symbol_sets': ['IF.PRD'],
# 设置所需k线类型,interval可以选取1分钟,5分钟,15分钟,30分钟,60分钟,日k,count为提前缓存的数目
'bars': [
{
'interval': '1min',
'count': 100,
'match':True
},
],
# 必填: 设置回测开始和结束日期 市场初始资金
'backtest': {
'start_date': 20181201,
'end_date': 20181230,
'cash': {'CF': 1000000}
},
# 选填:为group_only,则只响应on_handle_data;为single_only,则只响应on_bar;为both,则两个回调同时响应
'mode': 'both',
# 必填: 设置交易手续费
"commission": 0.0003
}
}
xquant.run_quant(config)
def on_initialize(api):
api.data_len = 100
# 交易参数设定
api.k1 = [-40.0, -3.0, -2.0, 2.0, 3.0, 40.0]
api.weight = [0.5, 0.3, 0.0, 0.3, 0.5]
api.trade_peroid = 60 # 每小时更新一次网格临界线
api.minute_num = 0
api.level = 3.0
api.volume = []
api.band = []
def on_before_market_open(api, date_now):
api.tradeday = date_now
api.trade_product = api.get_continuous_symbol("IFZ0.CFE")
# 查询初始资金
account = api.get_account(api.trade_product,"CF")
api.capital = account.cash_available
api.set_focus_symbols(api.trade_product)
def on_bar(api, bar):
print('on_bar', bar)
if (api.minute_num % api.trade_peroid) == 0:
# 获取过去300个数据计算临界线
data01 = api.get_bars_history(symbol=bar.symbol, timespan='1min', count=api.data_len)
close = np.array(data01["close"]).tolist()
api.band = np.mean(close) + np.array(api.k1) * np.std(close)
# 计算网格状态
grid = pd.cut([bar.close], api.band, labels=[0, 1, 2, 3, 4])[0]
# 更新计算交易量
api.volume = []
for weight in api.weight:
api.volume.append(lots(api, bar, weight))
api.minute_num += 1
# 查询持仓
position_long = api.get_symbol_position(symbol=bar.symbol, side='long')
position_short = api.get_symbol_position(symbol=bar.symbol, side='short')
if not position_short.pos_qty and not position_long.pos_qty and grid != 2:
if grid >= 3:
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close), side='long')
print("开多:", bar.symbol," qty:",api.volume[grid])
if grid <= 1:
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close), side='short')
print("开空:", bar.symbol," qty:",api.volume[grid])
elif position_long.pos_qty:
if grid >= 3:
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close), side='long')
print("加多:", bar.symbol," qty:",api.volume[grid])
elif grid == 2:
api.target_position(symbol=bar.symbol, qty=0,price= float(bar.close), side='long')
print("平多:", bar.symbol)
elif grid <= 1:
api.target_position(symbol=bar.symbol, qty=0,price= float(bar.close), side='long')
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close), side='short')
print("平多开空:", bar.symbol," qty:",api.volume[grid])
elif position_short.pos_qty:
if grid <= 1:
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close),side='short')
print("加空:", bar.symbol," qty:",api.volume[grid])
elif grid == 2:
api.target_position(symbol=bar.symbol, qty=0,price= float(bar.close),side='short')
print("平多:", bar.symbol)
elif grid >= 3:
api.target_position(symbol=bar.symbol, qty=0,price= float(bar.close),side='short')
api.target_position(symbol=bar.symbol, qty=api.volume[grid],price= float(bar.close),side='long')
print("平空开多:", bar.symbol," qty:",api.volume[grid])
def lots(api, data, weight):
# 获取账户资金计算下单手数
refdata = api.get_ref_data(data.symbol)
multiper = refdata.value_per_unit
return (int(api.capital * api.level * weight / data.close / multiper))
intradayStockTrade-日内回转交易(股票)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, absolute_import, unicode_literals, division
from xquant import *
import sys
import datetime
try:
import talib
except:
print('请安装TA-Lib库')
sys.exit(-1)
'''
本策略为股票日内回转交易。
1、首先买入600000.SH股票10000股底仓;
2、根据分钟数据计算MACD(12,26,9):
在MACD>0的时候买入100股;在MACD<0的时候卖出100股
3、每日操作的股票数不超过原有仓位,并于收盘前把仓位调整至开盘前的仓位
撮合周期为:600000.SH分钟数据
其他参数:按系统默认设置
'''
if __name__ == "__main__":
# 读取配置文件并启动策略
config = {
"user": "SDK-User", # 点击客户端管理平台右上角用户名可查看填写
"token": "SDK-Token", # 点击客户端管理平台右上角用户名可查看填写
"instance_id": "ID", # 客户端管理平台回测记录中本策略的回测ID,点击复制ID,粘贴此处即可
"login_endpoint": "https -h prx-01.upoem1.com -p 443", # 登录地址
"initialize": {
# symbols里设置单个股票或者其他有效的标的
'symbols': ['600000.SH'],
# fields缓存日频因子数据
'fields': ['PE'],
# 必填:设置所需k线类型,interval可以选取1分钟,5分钟,15分钟,30分钟,60分钟,日k,count为提前缓存的数目
'bars': [
{
'interval': "1min",
'count': 120,
'match':True
}
],
# 必填: 设置回测开始和结束日期 市场初始资金
"backtest": {
"start_date": 20200101,
"end_date": 20221101,
"cash": {'CS': 1000000},
},
# 选填:为group_only,则只响应on_handle_data;为single_only,则只响应on_bar;为both,则两个回调同时响应
'mode': 'single_only',
# 必填: 设置交易手续费
"commission": 0.0003,
}
}
xquant.run_quant(config)
def on_initialize(api):
# 设置标的股票
api.symbol = '600000.SH'
# 底仓
api.total = 10000
# 用于判定第一个仓位是否成功开仓
api.first = 0
# 日内回转每次交易100股
api.trade_n = 100
# 交易日
api.trade_date = [0, 0]
# 每日仓位
api.turnaround = [0, 0]
# 用于判断是否触发了回转逻辑的计时
api.ending = 0
# 当日可平仓数量
api.available_qty = 0
api.data_len = 120 # 数据长度
def on_before_market_open(api, date_now):
print("交易日:", date_now)
# 每日开盘前订阅行情
api.set_focus_symbols(api.symbol)
print("订阅%s的行情" % api.symbol)
# 查询当日可平仓数量
api.available_qty = api.get_symbol_position(symbol=api.symbol, side='long')
def on_bar(api, bar):
if api.first == 0:
# 购买10000股'600000.SH'股票
api.target_position(symbol=bar.symbol, qty=api.total,price = float(bar.close), side='long', remark="open new position")
print("open in new long postion by market order:", bar.symbol)
api.first = 1.
api.trade_date[-1] = bar.trade_date
# 每天的仓位操作
api.turnaround = [0, 0]
return
# 更新最新的日期
api.trade_date[0] = bar.trade_date
# 若为新的一天,获取可用于回转的昨仓
if api.trade_date[0] != api.trade_date[-1]:
api.ending = 0
api.turnaround = [0, 0]
if api.ending == 1:
return
# 若有可用的昨仓则操作
if api.total > 0 and api.available_qty.available_qty > 0:
# 获取时间序列数据
recent_data = api.get_bars_history(api.symbol, timespan='1min', count=api.data_len, price_mode='pre')
# 计算MACD线
macd = talib.MACD(recent_data['close'].values)[0][-1]
# 根据MACD>0则开仓,小于0则平仓
if macd > 0:
# 多空单向操作都不能超过昨仓位,否则最后无法调回原仓位
if api.turnaround[0] + api.trade_n < api.total:
# 计算累计仓位
api.turnaround[0] += api.trade_n
volume = api.total + api.turnaround[0] - api.turnaround[1]
api.target_position(symbol=bar.symbol, qty=volume, price= float(bar.close),side='long', remark="open new position")
print("open in new long postion by market order:%s : %i" % (bar.symbol, api.trade_n))
elif macd < 0:
if api.turnaround[1] + api.trade_n < api.total:
api.turnaround[1] += api.trade_n
volume = api.total + api.turnaround[0] - api.turnaround[1]
api.target_position(symbol=bar.symbol, qty=volume,price = float(bar.close), side='long', remark="close position")
print("close long postion by market order:%s : %i" % (bar.symbol, api.trade_n))
# 临近收盘时若仓位数不等于昨仓则回复所有仓位
date = datetime.datetime.fromtimestamp(bar.time_stop / 1000.0)
if int(date.timestamp()/1000000) >= 1455:
print("收盘前回复仓位")
symbol_position = api.get_symbol_position(symbol=api.symbol, side='long')
if symbol_position.pos_qty != api.total:
api.target_position(symbol=bar.symbol, qty=api.total,price = float(bar.close), side='long', remark="target position")
print("To target position:%d" % (api.total))
api.ending = 1
# 更新过去的日期数据
api.trade_date[-1] = api.trade_date[0]