十分钟快速入门

1、下载安装

下载链接https://academy.qmfquant.com/qimofang.zip

或在官网中根据需求选择不同版本:https://www.qmfquant.com/download

支持电脑配置:windows10 及以上系统,4 核 8G 配置,建议 4 核 16G 以上为佳;服务器建议为 windows 2016 server 4 核 8G 或 16G

2、注册期魔方账户

账号注册地址

方式1:https://academy.qmfquant.com/user-sign-2#tab-sign-up

图片描述

方式2:在客户端界面中也可以完成注册

账号密码找回:在客户端界面,点击登录密码的下方的“找回密码”,通过手机验证码方式,可以将账号密码重置

3、期货账户登录与下单

3.1 模拟账号的获取

如果您想使用模拟账户测试,通过下面地址可以一个申请模拟交易账号,申请通过后,客户会收到 simnow 发送的一条短信,短信里面有 6 位数字的账号,然后结合用户在页面注册的密码登录

模拟交易账号注册地址https://www.simnow.com.cn

3.2 期货账户登录

右下角期货登录-选择您所在期货账户的期货公司-输入账户密码-登录

3.3 选择指定品种

1.在下单面板输入正确合约代码

2.持仓面板搜索框选择指定品种

4、策略编写框架

初次使用期魔方平台,新增策略或编辑策略时,会弹出下载编辑器框,需要下载编辑器后才能编写和编译策略,不需要安装python环境,开箱即用,软件已经内置python12.9和pandas、numpy、ta_lib等众多常用库

点击策略-策略列表-新增策略或编辑策略,此时会弹出编译器,可在上面进行策略代码编写

一个完整的策略,一般包含 6 个结构性函数:on_tickon_initon_orderon_tradeon_erroron_stop,如果需要收线执行,还需添加 on_bar_run 函数

如果需要输入外置参数,还需添加外置参数配置类:class Params

"""
文件类型: 量化策略
帮助文档: https://qmfquant.com/static/doc/code/strategyEdit.html
期魔方,为您提供专业的量化服务
"""

"""
描述:策略外置参数配置的部分
是否必须编写:可选
编写具体规范见官网“策略编写”文档的策略编写的“外置参数编写”部分
"""
from pydantic import BaseModel, Field

class Params(BaseModel, validate_assignment=True):
    """参数映射模型"""
    """设置外置参数:手数"""
    #举例:交易手数的文字文本框的配置代码:volume: int = Field(default=1.0, title="交易手数")
    pass

"""
描述:该函数在策略被启动前运行一次;用于配置策略中需要的初始化逻辑;
必要的初始化部分请查询帮助文档
是否必须编写:必选
"""
def on_init(context):
    pass

"""
描述:主要的运行逻辑需要编写在 on_tick 函数中;策略成功启动后,每一次报价都会调用一次该函数;
是否必须编写:必选
"""
def on_tick(context):
    on_bar_run(on_bar, context) # 如不需要收线执行,则可以不写这行代码

"""
描述:报单回复接口,每次接收到报单时,该函数会被调用,报单信息在 order 对象中;
详细请查询帮助文档;
是否必须编写:可选
"""
def on_order(context, order):
    pass
    
"""
描述:报单回复接口,每次接收到成交单时,该函数会被调用,成交信息在 trade 对象中;
详细请查询帮助文档;
是否必须编写:可选
"""
def on_trade(context, trade):
    pass

"""
描述:当挂载账号出现错误操作时,该函数会被调用,错误信息在 err 对象中;
是否必须编写:可选
"""
def on_error(context, err):
    pass

"""
描述:当策略触发停止或报错时,调用该函数;可在函数中做一些结算的逻辑;
是否必须编写:可选
"""
def on_stop(context):
    pass

5、获取行情数据

5.1 get_kline 获取 K 线数据

说明

获取 K 线的开高低收、时间周期、成交量的序列。

接口案例

def on_tick(context):
    klines = get_kline("ru2501","M1",3)
    print(f"{klines}")

数据示例

{
    'close': [7687.0, 7686.0, 7647.0], 
    'open': [7687.0, 7687.0, 7686.0],
    'high': [7687.0, 7688.0, 7686.0],
    'low': [7687.0, 7686.0, 7647.0],
    'datetime': [Timestamp('2024-11-15 14:57:00'), 
                 Timestamp('2024-11-15 14:58:00'), 
                 Timestamp('2024-11-15 14:59:00')],
    'volume': [0.0, 3.0, 3966.0]
}

以上内容详情请见:获取K线数据

5.1 get_tick 获取tick数据

说明

获取指定合约 id 的当前最新报价

接口案例

def on_tick(context):
    # 获取合约 ag2412 当前的最新报价
    ag2412_tick = get_tick("ag2412")

数据示例

{
    "LastPrice": "", # 最新价格
    "LowerLimitPrice": 0, # 跌停价格
    "UpperLimitPrice": 0 # 涨停价格
    # 以下内容已省略
    # ...
}

以上内容详情请见:获取tick数据

6、获取账户信息

6.1 get_position 获取持仓信息

说明

返回一个 list,用于获取用户目前期货交易账户中所有持仓明细详情的函数。

接口案例

def on_init(context):
    # 获取当前持仓的明细
    position_info = get_position()
    print(f"{position_info}")

数据示例

[
    {
        'AccountID': 0,
        'ActiveTime': '9999',
        'CashIn': 0.0,
        'CloseAmount': 0,
        'CloseProfit': 0
    	# 以下展示内容已省略
    	# ...
    }
]

以上内容详情请见:获取持仓信息

6.2 get_account 获取 CTP 帐户信息

说明

获取当下已登录期货公司账户信息

接口案例

def on_init(context):
    account_info = get_account()
    print(f"{account_info}")

数据示例

{
    'AccountID': '182958',
    'Available': 20833162.898450002, # 可用资金
    'Balance': 20940449.198450003, # 账户总资金
    'BizType': '',
    'BrokerID': '9999',
    'CashIn': 0.0, 
    # 以下展示内容已省略
    # ...
}

以上内容详情请见:获取账户信息

7、报单/撤单

7.1 快捷报单

7.1.1 buy_open 开多仓

说明

建立一个多头仓位,默认采用市价单发送,会返回该订单唯一值

接口案例

def on_tick(context):
    res = buy_open(1) # 开单 1 手多单
    req_id = res["data"]["result"]["data"]["req_id"] # 通过这个方式可以拿到每次报单的唯一id

数据示例

# 以下是请求成功返回的结果。若请求失败:code 的值为非零 且 msg 会标记请求失败的原因)
{'code': 0, 'data': {...}, 'msg': 'ok'}

7.1.2 sell_open 开空仓

说明

建立一个空头仓位,默认采用市价单发送,会返回该订单唯一值

接口案例

def on_tick(context):
    res = sell_open(1) # 开单 1 手空单
    req_id = res["data"]["result"]["data"]["req_id"] # 通过这个方式可以拿到每次报单的唯一id

数据示例

# 以下是请求成功返回的结果。若请求失败:code 的值为非零 且 msg 会标记请求失败的原因)
{'code': 0, 'data': {...}, 'msg': 'ok'}

7.1.3 buy_close 平空仓

说明

结束一个空头仓位,默认采用市价单发送,如果存在今昨仓的持仓,平仓时会先平今,会返回该订单唯一值

接口案例

def on_tick(context):
    res = buy_close(1) # 平仓 1 手空单
    req_id = res["data"]["result"]["data"]["req_id"] # 通过这个方式可以拿到每次报单的唯一id

数据示例

# 以下是请求成功返回的结果。若请求失败:code 的值为非零 且 msg 会标记请求失败的原因)
{'code': 0, 'data': {...}, 'msg': 'ok'}

7.1.4 sell_close 平多仓

说明

结束一个多头仓位,默认采用市价单发送,如果存在今昨仓的持仓,平仓时会先平今,会返回该订单唯一值

接口案例

def on_tick(context):
    res = sell_close(1) # 平仓 1 手多单
    req_id = res["data"]["result"]["data"]["req_id"] # 通过这个方式可以拿到每次报单的唯一id

数据示例

# 以下是请求成功返回的结果。若请求失败:code 的值为非零且 msg 会标记请求失败的原因)
{'code': 0, 'data': {...}, 'msg': 'ok'}

以上内容详情请见:快捷报单

7.2 action_order 撤单

说明

涉及撤单时调用

接口案例

def on_tick(context):
    # 单子具体信息
    dict_data = {"Direction": "0",
          "OrderPriceType": "2",
          # ...
          # 单子中 key 必须包含 Symbol 、ExchangeID 、OrderSysID ,否则会存在撤单失败的情况,同 send_order 方法函数的用法举例,订单号 OrderSysID 为共12位右置的字符串,该字符串存在于 on_order 接口返回的订单信息
          "OrderSysID": "1863",
          "ExchangeID": "SHFE",
          "Symbol": "rb2501",
         }
    # 执行撤单
    res = action_order(dict)
    print(result)

数据示例

# 以下是请求成功返回的结果。若请求失败:code 的值为非零 且 msg 会标记请求失败的原因)
{'code': 0, 'data': {...}, 'msg': 'ok'}

以上内容详情请见:撤单

8、简单交易策略

策略 -> 策略列表 -> 我的策略 -> 新增策略 -> 填写策略名称,选择语言为 Python(已固定),添加注释说明 -> 确定

如果系统提示下载编写工具,就点击下载安装包,编辑器解压进度条 100% 后,会自动跳转到 VSCode 编辑器页面

以下是双均线策略代码举例: 当 5 日均线上穿 20 日均线时,平空买多; 当 5 日均线下穿 20 日均线时,平多卖空;

"""
文件类型: 量化策略
帮助文档: https://qmfquant.com/static/doc/code/strategyEdit.html
期魔方,为您提供专业的量化服务
"""

"""
描述:导入需要使用的库
是否必须编写:可选
"""
import numpy as np  # 导入 numpy 库便于进行数值计算
import talib as ta  # 导入 talib 库用于计算均线指标

"""
描述:策略外置参数配置的部分
是否必须编写:可选
编写具体规范见官网“策略编写”文档的策略编写的“外置参数编写”部分
"""
from pydantic import BaseModel, Field

class Params(BaseModel, validate_assignment=True):
    """参数映射模型"""
    """设置外置参数:手数"""
    # 举例:交易手数的文字文本框的配置代码:volume:int = Field(default=1, title="交易手数")
    pass

"""
描述:该函数在策略被启动前运行一次;用于配置策略中需要的初始化逻辑;
必要的初始化部分请查询帮助文档
是否必须编写:必选
"""
def on_init(context):
    context.base_instrument_id = BASE_SETTING.get("Instrument")  # 获取运行合约的名称
    context.base_period = BASE_SETTING.get("bPeriod")  # 获取运行合约的周期
    context.position = 0  # 理论持仓量(0 表示不持仓,正数表示多头持仓,负数表示空头持仓)

"""
描述:主要的运行逻辑需要编写在 on_tick 函数中;策略成功启动后,每一次报价都会调用一次该函数;
是否必须编写:必选
"""
def on_tick(context):
    # on_bar_run 让 on_bar 函数只在每一个 K 线新产生时运行一次,而不是每一个 tick 都运行一次,这样可以使策略收线运行
    on_bar_run(on_bar, context)

"""
描述:每一次新的 K 线数据产生时,调用该函数;
是否必须编写:可选
"""
def on_bar(context):
    # 获取当前合约当前周期的 K 线数据(计算 5 周期和 20 周期均线分别需要 5 根和 20 根 K 线数据,所以这里直接取 300 根 K 线数据进行计算)
    context.klines = get_kline(context.base_instrument_id, context.base_period, 300)
    # 获取 K 线数据中的收盘价数据
    context.close_array = context.klines.get("close")

    # 计算 5 周期和 20 周期均线,[:-1]是因为计算出来的数据包括了当前未闭合的 K 线数据,所以需要将当前 K 线数据去掉
    context.ma5_array = ta.SMA(np.asarray(context.close_array), 5)[:-1]  # np.asarray() 将列表转化为数组,方便 talib 库计算
    context.ma20_array = ta.SMA(np.asarray(context.close_array), 20)[:-1]  # np.asarray() 将列表转化为数组,方便 talib 库计算

    volume = 1  # 这里我们每次交易 1 手,也可以在外置参数中设置并在 on_init 函数中获取外置参数中设置的手数

    # 计算出来的 5 周期均线和20 周期均线数量不足以判断时,不进行交易
    if len(context.ma5_array) < 2 or len(context.ma20_array) < 2:
        return

    # 发生了死叉情况(即排除最新一根 K 线后,往前数第二根 5 周期均线小于 20 周期均线且往前数第一根 5 周期均线大于20 周期均线),如果当前持有多仓则平多仓
    if context.ma5_array[-2] >= context.ma20_array[-2] and context.ma5_array[-1] < context.ma20_array[-1]:
        if context.position > 0:  # 如果持有多仓
            sell_close(volume, context.base_instrument_id)  # 平多仓
            context.position = 0  # 更新持仓量
    # 发生了金叉情况(即排除最新一根 K 线后,往前数第二根 5 周期均线大于20 周期均线且往前数第一根 5 周期均线小于20 周期均线),如果当前持有空仓则平空仓
    elif context.ma5_array[-2] <= context.ma20_array[-2] and context.ma5_array[-1] > context.ma20_array[-1]:
        if context.position < 0:  # 如果持有空仓
            buy_close(volume, context.base_instrument_id)  # 平空仓
            context.position = 0  # 更新持仓量

    # 发生了金叉情况,如果当前没有持仓则开多仓
    if context.ma5_array[-2] <= context.ma20_array[-2] and context.ma5_array[-1] > context.ma20_array[-1]: 
        if context.position == 0:  # 如果没有持仓
            buy_open(volume, context.base_instrument_id)  # 开多仓
            context.position = volume # 更新持仓量
    # 发生了死叉情况,如果当前没有持仓则开空仓
    elif context.ma5_array[-2] >= context.ma20_array[-2] and context.ma5_array[-1] < context.ma20_array[-1]:
        if context.position == 0:  # 如果没有持仓
            sell_open(volume, context.base_instrument_id)  # 开空仓
            context.position = -volume  # 更新持仓量

"""
描述:当策略触发停止或报错时,调用该函数;可在函数中做一些结算的逻辑;
是否必须编写:可选
"""
def on_stop(context):
    pass

"""
描述:报单回复接口,每次接收到报单时,该函数会被调用,报单信息在 order 对象中;
详细请查询帮助文档;
是否必须编写:可选
"""
def on_order(context,order):
    pass

"""
描述:报单回复接口,每次接收到成交单时,该函数会被调用,成交信息在 trade 对象中;
详细请查询帮助文档;
是否必须编写:可选
"""
def on_trade(context,trade):
    pass

"""
描述:当挂载账号出现错误操作时,该函数会被调用,错误信息在 err 对象中;
是否必须编写:可选
"""
def on_error(context,err):
    pass

编辑好策略文件后,保存文件,在文件中单击右键,选择 Python 编译,编译输出中显示编译成功即可。

【注意】在编辑器中不要运行代码,否则会报错。

9、策略输出调试

9.1 put_log 推送日志

说明

推送日志到前端展示的方法

用户可以使用 put_log 函数打印日志,如果没有显示出来,可以将 level 参数提高级别到'ERROR'级别;

接口案例

# 以 INFO 级别示例:
def on_tick(context):
    text_data="这是一条日志消息内容"
    # 推送日志
    put_log(text_data,level="INFO")
    print(text_data)

数据示例

"""这是一条日志消息内容"""

以上内容详情请见:推送日志

9.2 日志地址

基于回测的日志信息在软件退出后会写入到用户目录的 AppData\Local\qmfquant\logs\backtest_server 下面

基于任务的日志信息在软件退出后会写入到用户目录的 AppData\Local\qmfquant\logs\task_server 下面

10、回测流程

回测-添加-设置基础参数(运行品种、测试模型、开始时间、结束时间这四项必需手动设置)-设置策略参数-点击右下角保存按钮-回测,回测完成后,可点详情,查看策略回测详细报告

11、实盘交易

任务-选择策略列表-双击策略-选择品种-设置周期-选择账号-设置策略默认参数和外置参数-提交-启动

12、学院论坛以及交流群

图片描述

更多内容

  1. 完整了解期魔方的更多功能及使用,请阅读期魔方软件操作文档
  2. 学习策略编写与更多策略案例,请阅读期魔方策略编写文档
  3. 学习指标编写与更多指标案例,请阅读期魔方指标编写文档
  4. 学习机器学习策略编写与更多案例,请阅读期魔方机器学习策略编写文档