聚宽(JoinQuant)、优矿(Uqer)等等都是非常好的量化交易平台,本文记录在JoinQuant上进行基础的策略框架。

首先,肯定先要注册一个JoinQuant账号,这个不废话。

在聚宽选择【策略研究】->【策略列表】

接下来,点击【新建策略】

接下来,就是这样一个页面:

  • 左边是代码区
  • 右边的设定包括回测的时间、初始资金、显示频率、Python版本

现在把里面内容都删了,写自己的东西。

最简单的交易策略

首先,要执行一个非常简单的交易策略

初始资金设置为10万,每天买100股平安银行

为了这个策略能执行,首先策略要符合“初始化+周期循环”框架:

初始化:选定要交易的股票为平安银行

每天循环:买100股的平安银行

初始化与循环,可以用以下方法写成代码(这是最新的方法):

def initialize(context):
    run_daily(period,time='every_bar')
    这里是用来写初始化代码的地方,例子中就是选定要交易的股票为平安银行

def period(context):
    这里是用来写周期循环代码的地方,例子中就是买100股的平安银行

关于contextperiod的内容,会在后面讲到。

接下来,如何基于这个框架来写代码?。

首先,要选定要交易的股票是平安银行:

g.security = '000001.XSHE'

买入100股平安银行(市价单写法):

order(g.security, 100)

完整代码为:

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = '000001.XSHE'

def period(context):
    order(g.security, 100)

第一次回测

接下来,把右边的频率设置成天,点击右边的回测按钮,就可以进行回测了,结果如下

其中,红线是基准收益(默认是沪深300指数,代表整个市场增长水平),蓝线是我们跑的。

周期循环具体是什么时候开始的呢?

  • 如果策略频率为天,是每个交易日开始生效,从9:30直到15:00(从股市开市到收市),所以例子中是每个交易日9:30开市循环就开始,一天一次地循环执行买入股票的操作。
  • 如果策略频率为分钟,是每个分钟开始时执行,所以例子中的买入股票的操作是每个交易日从9:30:00开始,然后9:31:00,直到14:59:00。接着下一天9:30:00,如此一分钟一次地循环执行的。

下单、函数、API

下面,来深入理解这些框架:

想了解它们怎么用,可以在API文档中查找,比如order - API按股价下单)

可以看到,order(security, amount, style=None, side='long', pindex=0, close_today=False),一共可以接收6个参数,其中:

  • security是标的代码;
  • amount是数量,单位为100,负数为卖出;
  • style决定下的是市价单还是限价单,默认None是市价单;
  • side决定是开空单还是开多单,股票只能开多
  • pindex是在多资金仓位时选择资金仓位,股票一般用不到

order函数是有返回值的,如果创建订单成功则返回Order对象,失败则返回None。

常见下单函数:

  • order(security,amount),这个刚才说了,就不讲了
  • order_target(security,amount),通过买卖,将股票仓位调到一定数量(单位:股)
  • order_value(security,value),买卖一定价值量(单位:元)股票。
  • order_target_value(security,value),通过买卖,将股票仓位调整至一定价值量(单位:元)

股票的拆分合并、分红,交易的税费,下单导致成交价向不利的方向波动,这些JoinQuant都考虑并且仿真处理了,这些暂时不关心。

context

首先,什么是context?

context顾名思义,就是上下文对象,存储了当前策略运行的时间点、所持股票、数量、持仓成本等等数据。

摘一张非常好的图片:

常用的context数据写法如下。

  • 当前时间 context.current_dt
  • 当前时间的“年-月-日”的字符串格式 context.current_dt.strftime("%Y-%m-%d")
  • 前一个交易日 context.previous_date
  • 当前可用资金 context.portfolio.available_cash
  • 持仓价值 context.portfolio.positions_value
  • 累计收益 context.portfolio.returns
  • 当前持有股票 context.portfolio.positions.keys()
  • 当前持有的某股票的开仓均价 context.portfolio.positions['xxxxxx.xxxx'].avg_cost
  • 当前持有的某股票的可卖持仓量 context.portfolio.positions['xxxxxx.xxxx'].closeable_amount

止损

当亏损到一定程度,就需要卖出止损,减少进一步的损失。

可以先根据context的数据得到持有股票的成本和现价,计算出该股票的盈亏程度,根据盈亏情况决定是否卖出股票,下面是个例子(跌出10%就止损):

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = '000001.XSHE'

def period(context):
    # 买入股票
    order(g.security, 100)
    #获得持仓成本
    cost = context.portfolio.positions['000001.XSHE'].avg_cost
    #获得股票现价
    price = context.portfolio.positions['000001.XSHE'].price
    ret = price / cost - 1
    print('成本价:', cost)
    print('现价',price)
    if ret < - 0.05:
        order_target('000001.XSHE', 0)
        print('触发止损')

再做个试验,在2016年6月13日买入,在2016年12月12日卖出

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = '000001.XSHE'

def period(context):
    
    current_dt = context.current_dt.strftime("%Y%m%d")
    if current_dt == '20160613':
        order_target_value(g.security, 100000)
    if current_dt == '20161212':
        order_target_value(g.security, 0)
    

循环、多股票策略

用list数据类型存储多个股票

可以用之前所学的内容,写多个股票的策略,把g.security弄成列表形式就OK了。

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = '000001.XSHE'

def period(context):
    order(g.security, 100)

因此,可以写一个简单的多股票策略:

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = ['000001.XSHE','000002.XSHE']

def period(context):
    for stk in g.security:
        order(stk, 100)
    

加上止损:

# 导入函数库
from jqdata import *

def initialize(context):
    run_daily(period,time='every_bar')
    g.security = ['000001.XSHE','000002.XSHE']

def period(context):
    for stk in g.security:
        order(stk, 100)
        cost=context.portfolio.positions[stk].avg_cost
        price=context.portfolio.positions[stk].price
        if cost == 0:
            continue
        ret=price/cost-1
        if ret<-0.05:
            order_target(stk,0)
            print('触发止损')

学习交流:
微信:ElijahMingLiu
Wechat

最后修改:2021 年 06 月 01 日 02 : 17 PM
如果觉得我的文章对你有用,请随意赞赏