功能不够用?使用C++编写通达信插件


通达信软件界面.png

通达信是一款非常流行的炒股软件,支持浏览行情、选股、预警等功能,它提供的公式系统非常好用,可以通过公式系统编写出我们想要的各种指标、买卖指示器等,甚至可以进行自动化交易评测。

在我使用通达信软件的10多年里,发现公式系统虽然功能非常丰富,但偶尔也会出现无法满足需求的时候。能不能自己写个插件,扩展软件的功能呢?答案是可以的,通达信软件提供了插件接口,插件实现接口就可以“插入”到通达信中,对通达信软件功能进行扩展。

虽然通达信软件提供了接口,但是相关的文档基本没有,只有头文件里有一点注释,外加一个非常简单的Demo。因此,我专门写这篇博客,讲解编写通达信插件的过程,让大家能少走弯路。

准备工作

开始编写前请做好准备工作,去通达信官网下载《通达信DLL函数编程规范》,下载地址是:
通达信帮助中心

创建项目

我的开发环境是Visual Studio 2017,实际上开发通达信插件可以使用Visual C++ 6.0到Visual C++ 2020的任意一个版本,本文就以Visual Studio 2017为例进行说明。

通达信插件是以动态库(DLL)方式插入的,因此需要创建一个动态库项目,你可以选择使用MFC、QT等等库,都可以。项目名称设置为DemoPlugin,如图:


创建动态库图1.png

项目创建好了以后把压缩包“通达信DLL函数编程规范.rar”中的“PluginTCalcFunc.h”拷贝到项目文件夹中,编写通达信插件只需要这个头文件,头文件的内容如下:

#ifndef __PLUGIN_TCALC_FUNC
#define __PLUGIN_TCALC_FUNC
#pragma pack(push,1) 

//函数(数据个数,输出,输入a,输入b,输入c)
typedef void(*pPluginFUNC)(int,float*,float*,float*,float*);

typedef struct tagPluginTCalcFuncInfo
{
    unsigned short        nFuncMark;//函数编号
    pPluginFUNC            pCallFunc;//函数地址
}PluginTCalcFuncInfo;

typedef BOOL(*pRegisterPluginFUNC)(PluginTCalcFuncInfo**);  

#pragma pack(pop)
#endif

实现插件

插件和通达信主程序的交互使用C风格的函数,在通达信的公式系统中使用“TDXDLL1”函数调用插件暴露的函数,并给函数传递参数,插件进行自己的处理,把返回值返回给通达信主程序,参数和返回值都是float类型的数组。下面来编写一个简单的函数,暴露给主程序的公式系统使用,请看代码:

dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "PluginTCalcFunc.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

void DemoFunction(int argCount, float* outResult, float* inArg0, float* inArg1, float* inArg2);

//加载的函数
PluginTCalcFuncInfo g_CalcFuncSets[] =
{
    {1, (pPluginFUNC)&DemoFunction},

    {0,NULL},
};

//导出给TCalc的注册函数
extern "C" __declspec(dllexport) BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun)
{
    if (*pFun == NULL)
    {
        (*pFun) = g_CalcFuncSets;
        return TRUE;
    }
    return FALSE;
}

void DemoFunction(int argCount, float* outResult, float* inArg0, float* inArg1, float* inArg2)
{
    for (int i = 0; i < argCount; i++)
    {
        outResult[i] = inArg0[i];
    }
}

这个插件实现了一个“DemoFunction”函数,该函数只是简单的把传入的第一个参数的值返回给通达信主程序。一个DLL可以暴露多个函数给通达信主程序,只需要在全局数组“g_CalcFuncSets”中添加一项。添加时请注意,函数的索引号不可重复,结尾的“{0,NULL}”必须保留。

编译插件

点击Visual Studio菜单“生成->生成解决方案”编译插件,编译时目标平台只能选择x86,因为通达信软件是32位的,如果插件编译成了64位则不能被加载。


插件目标平台.png

绑定插件

调用插件前需要先绑定插件DLL,步骤如下:

  1. 复制DLL文件“DemoPlugin.dll”到“通达信安装目录\T0002\dlls”中,插件如果有第三方依赖库也一并复制,如QT。
  2. 在通达信软件中绑定DLL,使用菜单“功能->公式系统->公式管理器”打开公式管理器,点击“DLL函数”按钮绑定DLL,如图:


绑定DLL.png

请记住你绑定的是第几号DLL,后面要用到。

调用插件

1.在通达信公式管理器中点击“新建”按钮,创建一个新的公式,设置公式名称为“DEMO”,公式代码填入“DEMO:TDXDLL2(1,CLOSE * 0.9, 0, 0);”,如图:


通达信公式编辑器.png

“TDXDLL2”需要替换成你绑定的DLL的索引,如果你绑定的是第1号DLL那么就写“TDXDLL1”,支持“TDXDLL1”到“TDXDLL10”。
2.点击“确定”按钮保存公式。
3.关闭“公式管理器”,回到主界面。
4.使用副图菜单“选择副图指标”选中刚才创建的“DEMO”公式,如图:


副图菜单.png
选择副图指标对话框.png

5.选择“DEMO”公式,点击“确定”按钮,完成后你应该会看到类似下图的结果:


公式效果.png

至此,从插件编写到插件使用,一个完整闭环的过程就介绍完了。不知道你注意到没有,在通达信公式中“DEMO:TDXDLL2(1,CLOSE * 0.9, 0, 0);”的第二个参数填写的是“CLOSE * 0.9”,它的意思是收盘价 * 0.9,看起来是一个值乘以了0.9,但是在插件中接收到的参数类型却是float*,是一个数组,包含多个值。这就是通达信公式和c++插件之间概念的差异,站在c++角度看,通达信公式中的所有数据都是数组,连时间也是数组,在插件中处理时需要注意这点。

插件的调试

通达信软件有反调试机制,不能直接附加调试器到通达信进程进行调试。只能使用日志进行调试,把信息输出到日志中,通过查看日志定位Bug。

骚操作

通达信插件中可以使用完全的c++功能,集成第三方库也没有限制,存在无限的骚操作余地,仅列举几条现在想到的:

  • 集成libcurl,调用WebApi获取数据,利用通达信软件强大的画图能力绘制图表,进行股票分析
  • 集成mysql客户端,使用数据库中存储的数据进行选股
  • 集成聚宽客户端,进行量化分析

芸芸小站首发,阅读原文:


最后编辑:2021年05月11日 ©版权所有,转载须保留原文链接