使用SWIG封装恒生极速UFT接口(Python3)

使用SWIG封装恒生极速UFT接口(Python3)

一、准备工作

  • 参考资料
    • CTP Python API及Demo(利用Swig 封装)Windows版(traderapi),20191208,作者:景色正好。
    • Swig转换C++接口中文乱码解决方案,作者:景色正好
    • SWIG 简介PDF
    • 官方教程 SWIG and Python
    • Demo只能登录一个账户、只有主线程运行,了解Python多线程可同步多项任务。
    • 多任务也能使用异步实现。
    • 景色大佬在CSDN上的答疑整理。
  • 安装环境
    • Python 3.7.6 | packaged by conda-forge | (default, Mar 23 2020, 22:22:21) [MSC v.1916 64 bit (AMD64)] on win32
    • 恒生极速UFT开发包64位
    • Visual Studio 2019 社区版
  • 下载
    • swig 最新安装包,解压缩至C:\,例如 “C:\swigwin”
    • 添加环境变量到path, 比如: C:\swigwin, 打开cmd 输入 swig –help,检测是否安装成功
    • 从qq群(恒生极速API交流群,QQ群号: 586525357 )下载最新的恒生极速API开发包,官网搜一下也可以。
  • 其他
    • 本文后续更新在语雀上,主要因为语雀的PC版使用非常方便。点击这里查看最近更新。

二、SWIG接口文件

  • 将API开发包解压,并将开发包 include*.h 的头文件复制至sdk对应的文件夹,如win64,放一起
  • 创建swig接口文件HSTradeApi.i,这是交易核心部分。HSMdApi.i 可以模仿编写。
%module(directors="1") HSTradeApi 
%{ 
#include "HSTradeApi .h"
%}

%feature("director") CHSTradeSpi; 
%include "HSDataType.h"
%include "HSStruct.h" 
%include "HSTradeApi.h"   
  • 【可选】为解决中文乱码问题,按景色正好2019.12 增加乱码处理。 建议先把接口跑通了,再增加这一部分,便于查找错误原因。
%module(directors="1") HSTradeApi 
%{ 
#include "HSTradeApi .h"
#include 
#include 
#include 
#include 
using namespace std;
#ifdef _MSC_VER
const static locale g_loc("zh-CN");
#else    
const static locale g_loc("zh_CN.GB18030");
#endif
%}

%typemap(out) char[ANY], char[] {
    const std::string &gb2312($1);
    std::vector<wchar_t> wstr(gb2312.size());
    wchar_t* wstrEnd = nullptr;
    const char* gbEnd = nullptr;
    mbstate_t state = {};
    int res = use_facet<codecvt<wchar_t, char, mbstate_t> >
        (g_loc).in(state,
            gb2312.data(), gb2312.data() + gb2312.size(), gbEnd,
            wstr.data(), wstr.data() + wstr.size(), wstrEnd);
 
    if (codecvt_base::ok == res)
    {
        wstring_convert<codecvt_utf8<wchar_t>> cutf8;
        std::string result = cutf8.to_bytes(wstring(wstr.data(), wstrEnd));       
        resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size()); 
    }
    else
    {
        std::string result;
        resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size()); 
    }
}

%feature("director") CHSTradeSpi; 
%include "HSDataType.h"
%include "HSStruct.h" 
%include "HSTradeApi.h"   
  • 打开cmd,cd 进入win64文件夹,运行 swig -threads -py3 -c++ -python HSTradeApi.i
    • 此时,会有一个警告,如下,这个可以忽略。

HSTradeApi.h(25) : Warning 514: Director base class CHSTradeSpi has no virtual destructor.
这是因为 HSTradeApi.h 里的 CHSTradeSpi 类是不带析构函数的抽象基类,包装成Python的抽象类时SWIG也不会自动添加析构函数。如果用 Python abc module 生成抽象类,则会自动加上析构函数。因此,按Python的标准,会出一个警告。

  • 我直接使用Python 64bit,SWIG并不需要设置Python 头文件之类。

  • 正常没有报错,就会生成以下三个文件。
    使用SWIG封装恒生极速UFT接口(Python3)_第1张图片

    .h.cxx文件是用于包装原来C++接口的文件,下面要用。.py文件是完成后python import的接口文件,验证测试时会用到。

  • 在一些情况下,_wrap.cxx文件会出现错误的include,比如下方的文件名中多了一个空格,进入VS2019手工修改掉。
    使用SWIG封装恒生极速UFT接口(Python3)_第2张图片

三、获得pyd动态库

  • VS2019中,建立C++工程。

使用SWIG封装恒生极速UFT接口(Python3)_第3张图片

  • 如果python环境是64位, 则新建C++项目也必须是64位。

    • 使用UFT文件夹中的win64 开发文件
      在这里插入图片描述

    • 选择Build --> configuration manager 进行如下设置。
      使用SWIG封装恒生极速UFT接口(Python3)_第4张图片

    • 项目属性也选择 X64
      使用SWIG封装恒生极速UFT接口(Python3)_第5张图片

      如果是32位Python, 所有设置都对应win32。

  • VS2019 Project 属性设置

    使用SWIG封装恒生极速UFT接口(Python3)_第6张图片

  • 运行DEBUG检查一下,没问题再做之后的步骤。

  • 将SWIG生成的2个文件,以及相关的lib文件和头文件,移入 _HSTradeApi Project文件夹
    使用SWIG封装恒生极速UFT接口(Python3)_第7张图片

  • 选择 Release 版本,对项目Debug, 在项目文件夹下,会出现Release文件夹。x64出现在 …\x64\Release 内
    使用SWIG封装恒生极速UFT接口(Python3)_第8张图片

  • 找到正确的Release文件夹地址,将其中的 _HSTradeApi.dll 的扩展名更名为 pyd

四、完成接口

  • 在之前各步骤中找出以下三个文件,放入一个新文件夹。
    使用SWIG封装恒生极速UFT接口(Python3)_第9张图片

    其中,pyd为上一步生成的文件,在Release文件夹中;HSTradeApi.dll 在API开发文件夹中;.py 在SWIG生成的文件中。

  • 将上述三个文件,复制入Python环境中。打开并修改HSTradeApi.py 文件中的错误部分,一般对应python 3.7 及以上
    使用SWIG封装恒生极速UFT接口(Python3)_第10张图片

五、测试

from pytradeapi import HSTradeApi as api

"""
此处自己修改、添加账户信息
"""
AccountID = 'ACCOUNTID'
Password = 'PASSWORD'
AppID = 'APPID'
AuthCode = 'AuthCode'

# 子类继承时,重写(override)基类方法。
class CTradeSpi(api.CHSTradeSpi):

    def __init__(self, tapi):
        api.CHSTradeSpi.__init__(self)
        self.tapi = tapi  # 在spi内添加一个api实例

    def OnFrontConnected(self) -> "void":
        # 系统先尝试连接服务器,成功后再继续
        print("OnFrontConnected")
        authfield = api.CHSReqAuthenticateField()
        authfield.AccountID = ACCOUNTID
        authfield.Password = PASSWORD
        authfield.AppID = APPID
        authfield.AuthCode = AuthCode
        self.tapi.ReqAuthenticate(authfield, 0)
        print("send ReqAuthenticate ok")

    def OnFrontDisconnected(self, nResult: 'int') -> "void":
        print("OnFrontDisconnected")
        print(self.tapi.GetApiErrorMsg(nResult))


tradeapi = api.NewTradeApi('./log/')  # 创建tradeAPI实例
tradespi = CTradeSpi(tradeapi)  #
tradeapi.RegisterFront(FrontAddr)  # 
tradeapi.RegisterSpi(tradespi)  #
tradeapi.Init(LicenseFile)  # 启动连接
# tradeapi.Join()  #Join函数是使得函数阻塞在这里,等待api实例创建的内部线程的结束
time.sleep(5)

"""此处加入其他代码,完成后断开连接"""

tradeapi.Release()  # 断开连接

六、后续工作

  1. 上述接口中增加编码转换,不然对于中文字符,Python里收到的都是乱码。
  2. 完善登录时的流程,因为每天第一次登录时都要确认结算单。这和CTP基本相同,参考着做就行。
  3. 一样的方法,制作Python行情接口(HSMdSpi)。
  4. 交易功能,单账户交易如开仓检查、平仓检查等,以及多账户交易。

你可能感兴趣的:(使用SWIG封装恒生极速UFT接口(Python3))