AlgoPlus 2.0股票量化交易SDK范例解析

  • Post author:
  • Post category:其他


AlgoPlus 2.0是使用c++语言开发的全市场量化交易SDK,旨在提高量化交易开发效率、促进量化交易技术交流。

本文将通过一个范例介绍如何使用AlgoPlus 2.0实现股票模拟交易。

首先,先给大家介绍AlgoPlus 2.0的关键方法。




AlgoPlus关键方法



初始化方法

/// pLoginField中存放了登录所需要的信息;
/// pMarketDataCallback是行情事件回调函数;
/// pOrderCallback是订单事件回调函数;
/// pEventCallback是其他事件回调函数指针;
/// 初始化完成后,pLoopCallback在一个独立线程中被反复执行;
CBaseTrader* init(short nRunID, CAPLoginField* pLoginField, FAPOnMarketDataFunctionType pMarketDataCallback, FAPOnOrderFunctionType pOrderCallback, FAPOnEventFunctionType pEventCallback, FAPOnLoopFunctionType pLoopCallback)

初始化时需要提供必要的登录信息,以及事件回调函数。这些回调函数都是由用户定义,由AlgoPlus在事件发生时调用。用户在回调函数中实现事件处理逻辑。



订阅方法

/// 省略交易所,优先匹配A股标的;
/// 如果交易代码不重复,可以省略交易所,且一次订阅不同交易所的标的;
/// 如果交易代码存在重复情况,需指定交易所,且订阅标的必须属于该交易所。
TAPErrorIDType subscribe(CBaseTrader* pAPTrader, char** ppStandardID, int nCount, const char* szExchangeID)



报单方法

/// 买入指定的数量;
CAPOrderField* buy(CBaseTrader* pAPTrader, const char* szStandardID, int nOrderVolume, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);
/// 先根据订单类型确定报单价格,再计算金额对应的符合交易所规则的报单数量;
CAPOrderField* buyAmount(CBaseTrader* pAPTrader, const char* szStandardID, double dAmount, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);
/// 以可用资金为基数计算买入金额,最终换算成买入数量
CAPOrderField* buyRatio(CBaseTrader* pAPTrader, const char* szStandardID, double dRatio, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);

/// 卖出指定的数量,超过可用持仓则卖出全部可用持仓;
CAPOrderField* sell(CBaseTrader* pAPTrader, const char* szStandardID, int nOrderVolume, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);
/// 先根据订单类型确定报单价格,再计算金额对应的符合交易所规则的报单数量;
CAPOrderField* sellAmount(CBaseTrader* pAPTrader, const char* szStandardID, double dAmount, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);
/// 以可用持仓为基数计算卖出数量;
CAPOrderField* sellRatio(CBaseTrader* pAPTrader, const char* szStandardID, double dRatio, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);

/// 调仓指令,将持仓调整至目标数量。
CAPOrderField* balanceToLongValue(CBaseTrader* pAPTrader, const char* szStandardID, double dTargetValue, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);
/// 调仓指令,将持仓调整至目标金额。
CAPOrderField* balanceToLongVolume(CBaseTrader* pAPTrader, const char* szStandardID, int nTargetVolume, char chOrderType, double dOrderPrice, short nOrderMark, const char* szExchangeID);



撤单方法

/// 根据OrderID撤销某个特定的订单
TAPErrorIDType cancelOrder(CBaseTrader* pAPTrader, int nOrderID);
/// 撤销某只股票所有的未成成交订单
TAPErrorIDType cancelOrderByStandardID(CBaseTrader* pAPTrader, const char* szStandardID, const char* szExchangeID);
/// 撤销某交易所所有未成交订单
TAPErrorIDType cancelOrderByExchangeID(CBaseTrader* pAPTrader, const char* szExchangeID);
/// 撤销账号所有未成交订单
TAPErrorIDType cancelOrderAll(CBaseTrader* pAPTrader);

我们还需要一个交易环境,这里用的是N视界(

http://www.n-sight.com.cn

)提供的股票模拟交易环境。



N视界股票模拟交易环境

N视界有三套股票模拟交易环境,其中一套的交易时间与实盘一致:

交易前置 tcp://210.14.72.11:4400
行情交易 tcp://210.14.72.11:4402

另外两套是7*24小时环境:

A:
7*24股票模拟环境交易前置 tcp://210.14.72.15:4400
7*24股票模拟环境行情前置 tcp://210.14.72.15:4402

B:
7*24股票模拟环境交易前置 tcp://210.14.72.16:9500
7*24股票模拟环境行情前置 tcp://210.14.72.16:9402



范例与解析

import AlgoPlus as ap

def stock_on_event(event_id, field, islast, error_id, error_msg):
    field = ap.decode_ctp_event_field(event_id, field)
    print(f"-------")
    print(f"on_event -> EventID:{event_id},LastFlag:{islast},ErrorID:{error_id},ErrorMsg:{error_msg}")
    print(f"on_event -> Content: {field}")
    print(f"-------")

@ap.ap_marketdata_callback_wraps
def stock_on_marketdata_event(data):
    print(f"-------")
    print(f"on_marketdata -> {data}")
    print(f"-------")

@ap.ap_order_callback_wraps
def stock_on_order_event(event_id, order, position, cash):
    print(f"-------")
    print(f"on_order -> EventID:{event_id},UsableCash:{cash}")
    print(f"on_order -> {order}")
    print(f"on_order -> {position}")
    print(f"-------")

def stock_on_loop():
    global counter
    global standard_list
    global trader
    global last_order

    counter += 1
    if counter == 1:
        ap.cancelOrderAll(trader)
        print(f"-------")
        print(f"loop:{counter} -> cancelOrderAll")
        print(f"-------")
    elif counter == 100:
        print(f"-------")
        for item in standard_list:
            order = ap.buy(trader, item, 100, ap.ENUM_OrderType_FrontierLimitAndWait, 0)
            if order is not None:
                print(f"loop:{counter} -> buy UpperLimitPrice -> ErrorID:{order.ErrorID},StandardID:{item},Volume:{100},Price:{order.OriginalPrice}")
        print(f"-------")
    elif counter == 150:
        print(f"-------")
        for item in standard_list:
            order = ap.buy(trader, item, 100, ap.ENUM_OrderType_HomeBestLimitAndWait, 0)
            if order is not None:
                print(f"loop:{counter} -> buy HomeBestPrice -> ErrorID:{order.ErrorID},StandardID:{item},Volume:{100},Price:{order.OriginalPrice}")
                if order.ErrorID == 0:
                    last_order = order
        print(f"-------")
    elif counter == 200:
        if last_order is not None:
            ap.cancelOrder(trader, last_order.OrderID)
            print(f"-------")
            print(f"loop:{counter} -> cancelOrder last_order -> StandardID:{last_order.StandardID}")
            print(f"-------")
    elif counter == 250:
        ap.cancelOrderAll(trader)
        print(f"-------")
        print(f"loop:{counter} -> cancelOrderAll")
        print(f"-------")

if __name__ == '__main__':

    login = ap.CAPLoginField()
    login.License = ""
    login.UserType = ap.ENUM_UserType_NSIGHTStock
    login.UserID = ""
    login.InvestorID = ""
    login.Password = ""
    login.TraderFront = "tcp://210.14.72.15:4400"
    login.MdFront = "tcp://210.14.72.15:4402"
    login.ConnectTimeout = 0
    login.TaskExecuteGap = ap.MICROSECONDS_IN_SECOND * 2
    login.BasePath = "./"

    last_order = None
    counter = 0
    standard_list = ["600000", "000001", "300001"]
    trader = ap.init(0, login, stock_on_marketdata_event, stock_on_order_event, stock_on_event, stock_on_loop)
    if trader is not None:
        ap.subscribe(trader, standard_list)
        ap.loop()
    else:
        init_error_id = ap.getInitError()
        print(f"init_error -> InitErrorID:{init_error_id}")

  • stock_on_event

    是我们定义的其他事件回调函数。ap.decode_ctp_event_field函数根据event_id将c++结构体转成pyhon对象。

在这里插入图片描述

如图所示,初始化阶段分别触发ENUM_EventID_DayRolling(10008)事件和ENUM_EventID_Ready(10009)事件。


  • stock_on_marketdata_event

    是我们定义的行情通知事件的回调函数。@ap.ap_marketdata_callback_wraps是一个装饰器,可以将c++行情结构体转成python对象。

在这里插入图片描述

  • 初始化完成之后,

    stock_on_loop

    在一个独立线程中被反复执行。

在这里插入图片描述

如图所示在第100次执行时,以涨停板限价分别买入100股600000、000001、300001。使用的报单指令是

buy

,订单类型型是

ENUM_OrderType_FrontierLimitAndWait

在这里插入图片描述

在第150次执行时,以本方最优限价分别买入100股600000、000001、300001。使用的报单指令是

buy

,订单类型型是

ENUM_OrderType_HomeBestLimitAndWait

其中,

stock_on_order_event

负责实时推送订单状态变化、成交金额变化。@ap.ap_order_callback_wraps是一个装饰器,将c++订单结构体、持仓结构体装成python对象。




客户端

在N视界官网下载页面(

http://n-sight.com.cn/u/w/download/download.html

)定制服务专区下载剑鱼星终端。

登录前选择N视界仿真交易地址:

在这里插入图片描述

在这里插入图片描述

登录后可监测账户交易状态:

在这里插入图片描述

如图所示,这是范例报单的情况,前三笔涨停板限价单全都成交了,后三笔本方最优限价单成交了两笔。第一次撤单使用的时cancelOrder,撤单对象是300001,这笔订单已经成交,所以未执行。第二次撤单使用的指令时cancelOrderAll,撤单对象是所有未成交单,所以600000此时被撤销。




项目地址



版权声明:本文为AlgoPlus原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。