pu369com

功能不够用?使用C++编写通达信插件及接入Python(二)

参考:https://zhuanlan.zhihu.com/p/613157262

一、准备工作(参考上一篇)

安装 VS2019 

安装pycharm

下载  http://help.tdx.com.cn/book.asp 《通达信DLL函数编程规范.rar》

二、下载python3.x的32位版本,,随便找个32位版就行了。

我准备下载Windows embeddable package (32-bit),然而下载速度感人,于是参考https://blog.csdn.net/m0_64336780/article/details/123534308

从 https://mirrors.huaweicloud.com/python/ 下载了   python-3.11.3.exe 安装

由于我已经安装了python 64 位的,所以安装后,要调整环境变量,将32位的环境变量调到上面,就切换成32位了。需要63位时,再将64位的环境变量调整到上面即可。

三、从   通达信DLL函数编程规范  里的项目开始

1.修改VS2019,勾选  windows10 SDK

2. 用Visual studio 打开 “TestPluginTCale.dsw”文件

出现“评审项目和解决方案更改”  ,直接 确定

出现迁移报告,存在错误

3.解决BUG - 修改项目属性

在解决方案资源管理器中,项目的  TestPluginTCale上右键 属性  

在弹出框的  配置属性  c/c++  常规  中,将  “调试信息格式”的选项更改为“程序数据库(/Zi)”

               在 配置属性  c/c++  代码生成  中 “启用最小重新生成”设为“否(/Gm-)”

               在 配置属性  c/c++  代码生成  中 “启用函数级链接”设为“是(/Gy)”

               在 配置属性  链接器  常规   附加库目录 

             输入 D:\Python\python31132\libs  (根据你的32位python安装位置确定)之后,值变为:D:\Python\python31132\libs;%(AdditionalLibraryDirectories)

              如果添加后,vs报错,说什么python3x_d找不到,那就在安装目录下的libs(不是lib)里找到python3x.lib,复制一份改个名,改成vs要求的文件名就行了。总之,vs说差什么文件,改成vs要求的文件名就可以了。

四、改写TCalcFuyncSets.cpp如下:

#include "stdafx.h"

#include "TCalcFuncSets.h"

#include "Python.h" //严重注意,一定要include这个。

//生成的dll请拷贝到通达信安装目录的T0002/dlls/内,再在公式管理器进行绑定

//有人老是无法正常绑定,这里给出两种解决方案,任选其一,本人喜欢第二种

//1、不运行快捷方式,直接点开通达信目录里的执行文件

//2、运行快捷方式,但需要将快捷方式里的起始位置清空

void CallFunction(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc, char* funcName)

{

	//填上自己的32位python安装目录,当然,你的python也可以直接装在这个目录下。

	Py_SetPythonHome(L"C:\\Python31132"); //用这个版本的python来执行python文件

	Py_Initialize(); //初始化python接口



	//初始化使用的变量

	PyObject* pModule = NULL;

	PyObject* pFunc = NULL;

	PyObject* pName = NULL;



	//获得绝对路径,保证可以访问到 .py文件

	//这里需要注意的时候,运行通达信时,找到的路径是通达信的安装路径,所以需要把子路径补充进去

	PyRun_SimpleString("import os,sys");

	PyRun_SimpleString("sys.path.append(os.getcwd()+ '/T0002/dlls/')");



	//当前的测试python文件名是TDXPYDLL.py,只需要写文件的名称就可以了。也可以换个名字,但需要把名字改了。

	pModule = PyImport_ImportModule("TDXPYDLL");



	//获取调用的函数

	pFunc = PyObject_GetAttrString(pModule, funcName);



	//定义一个与数组等长的PyList对象数组

	PyObject* HList = PyList_New(DataLen);

	PyObject* LList = PyList_New(DataLen);

	PyObject* CList = PyList_New(DataLen);



	//定义一个元组,有四个变量的参数元组

	PyObject* paramTuple = PyTuple_New(4);



	//PyList对象的每个元素赋值PyList_Size(HList),以便传入价格序列

	for (int i = 0; i < DataLen; i++)

	{

		PyList_SetItem(HList, i, Py_BuildValue("f", pfINa[i]));

		PyList_SetItem(LList, i, Py_BuildValue("f", pfINb[i]));

		PyList_SetItem(CList, i, Py_BuildValue("f", pfINc[i]));

	}



	//向python传参数

	PyTuple_SetItem(paramTuple, 0, Py_BuildValue("i", DataLen));//第一个参数

	PyTuple_SetItem(paramTuple, 1, HList); //1:表示序号。第二个参数。

	PyTuple_SetItem(paramTuple, 2, LList); //2:表示序号。第三个参数。

	PyTuple_SetItem(paramTuple, 3, CList); //3:表示序号。第四个参数。



	//使用C++的python接口调用该函数

	PyObject* pReturn = PyObject_CallObject(pFunc, paramTuple);



	if (pReturn) //类型检查

	{

		for (int i = 0; i < DataLen; i++)

		{

			//PyObject *Item = PyList_GetItem(pReturn, i);//获取List对象中的每一个元素

			float result;

			PyArg_Parse(PyList_GetItem(pReturn, i), "f", &result);//f表示转换成浮点变量

			pfOUT[i] = result;

		}

	}

	////用完接口得放掉,呼应前面的Py_Initialize();

	Py_Finalize();



}



void TestPlugin1(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin1");

}



void TestPlugin2(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin2");

}





void TestPlugin3(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin3");

}





void TestPlugin4(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin4");

}



void TestPlugin5(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin5");

}



void TestPlugin6(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc)

{

	CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin6");

}



//加载的函数,这里的序号和上面函数对应,这只是绑了六个,想多绑的自己加

PluginTCalcFuncInfo g_CalcFuncSets[] =

{

{1,(pPluginFUNC)&TestPlugin1},

{2,(pPluginFUNC)&TestPlugin2},

{3,(pPluginFUNC)&TestPlugin3},

{4,(pPluginFUNC)&TestPlugin4},

{5,(pPluginFUNC)&TestPlugin5},

{6,(pPluginFUNC)&TestPlugin6},

{0,NULL},

};



//导出给TCalc的注册函数

BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun)

{

	if (*pFun == NULL)

	{

		(*pFun) = g_CalcFuncSets;

		return TRUE;

	}

	return FALSE;

}

  结果提示没头文件,python.h

参考:https://blog.csdn.net/JLinkTwo/article/details/87917504  用   pip install python-dev  安装

再参考:https://blog.csdn.net/weixin_44575152/article/details/114186758     对 配置属性  VC++目录   外部包含目录   进行编辑,  加入了  python.h所在目录: D:\Python\python31132\include

生成解决方案
又提示: 无法打开文件“python311_d.lib

于是将D:\Python\python31132\libs下的 python311.lib 复制 为  python311_d.lib

终于成功了

到了这里, Dll写完了,编译成32位TestPluginTCale.dll放到T0002/dlls目录里。然后创建一个TDXPYDLL.py,该文件同样需要放在T0002/dlls内。

def TestPlugin1(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result
def TestPlugin2(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result
def TestPlugin3(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result
def TestPlugin4(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result
def TestPlugin5(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result
def TestPlugin6(N: int, H: list, L: list, C: list):
    for i in range(1, N):
        result[i] = i
    return result

按上一篇 绑定DLL,写demo公式,结果通达信死机

后来发现 dll 源文件 中有一句忘记改了:

Py_SetPythonHome(L"C:\\Python31132"); //用这个版本的python来执行python文件

改为Py_SetPythonHome(L"D:\\Python\\python31132");

重新生成dll,替换,不要从快捷方式而是从所在目录中启动TdxW.exe,看似成功了,python脚本似乎也运行了。然而得不到输出

又参照网贴,将TestPlugin2改为如下代码:

def TestPlugin2(N: int, H: list, L: list, C: list):
    result=[]
    for i in range(1, N):
        temp = i * 6.0
        result.append(temp)    
    return result

  终于成功了

上面的temp也可以:temp = (H[i]+L[i]+C[i])*1.0

说明:在python代码中,可以  import os  

然后用os.mkdir('你的目录')在通达信运行目录中生成文件夹

或者用

        log = open('r.txt', 'a')
        print(“相关数据”, file=log)

  更明显地看到效果。

 

posted on 2023-04-17 16:40  pu369com  阅读(1408)  评论(0编辑  收藏  举报

导航