
通达信是一款非常流行的炒股软件,支持浏览行情、选股、预警等功能,它提供的公式系统非常好用,可以通过公式系统编写出我们想要的各种指标、买卖指示器等,甚至可以进行自动化交易评测。
在我使用通达信软件的10多年里,发现公式系统虽然功能非常丰富,但偶尔也会出现无法满足需求的时候。能不能自己写个插件,扩展软件的功能呢?答案是可以的,通达信软件提供了插件接口,插件实现接口就可以“插入”到通达信中,对通达信软件功能进行扩展。
虽然通达信软件提供了接口,但是相关的文档基本没有,只有头文件里有一点注释,外加一个非常简单的Demo。因此,我专门写这篇博客,讲解编写通达信插件的过程,让大家能少走弯路。
准备工作
开始编写前请做好准备工作,去通达信官网下载《通达信DLL函数编程规范》,下载地址是:
通达信帮助中心
创建项目
我的开发环境是Visual Studio 2017,实际上开发通达信插件可以使用Visual C++ 6.0到Visual C++ 2020的任意一个版本,本文就以Visual Studio 2017为例进行说明。
通达信插件是以动态库(DLL)方式插入的,因此需要创建一个动态库项目,你可以选择使用MFC、QT等等库,都可以。项目名称设置为DemoPlugin,如图:

项目创建好了以后把压缩包“通达信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位则不能被加载。

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

请记住你绑定的是第几号DLL,后面要用到。
调用插件
1.在通达信公式管理器中点击“新建”按钮,创建一个新的公式,设置公式名称为“DEMO”,公式代码填入“DEMO:TDXDLL2(1,CLOSE * 0.9, 0, 0);”,如图:

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


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

至此,从插件编写到插件使用,一个完整闭环的过程就介绍完了。不知道你注意到没有,在通达信公式中“DEMO:TDXDLL2(1,CLOSE * 0.9, 0, 0);”的第二个参数填写的是“CLOSE * 0.9”,它的意思是收盘价 * 0.9,看起来是一个值乘以了0.9,但是在插件中接收到的参数类型却是float*,是一个数组,包含多个值。这就是通达信公式和c++插件之间概念的差异,站在c++角度看,通达信公式中的所有数据都是数组,连时间也是数组,在插件中处理时需要注意这点。
插件的调试
通达信软件有反调试机制,不能直接附加调试器到通达信进程进行调试。只能使用日志进行调试,把信息输出到日志中,通过查看日志定位Bug。
骚操作
通达信插件中可以使用完全的c++功能,集成第三方库也没有限制,存在无限的骚操作余地,仅列举几条现在想到的:
- 集成libcurl,调用WebApi获取数据,利用通达信软件强大的画图能力绘制图表,进行股票分析
- 集成mysql客户端,使用数据库中存储的数据进行选股
- 集成聚宽客户端,进行量化分析
芸芸小站首发,阅读原文:http://xiaoyunyun.net/index.php/archives/53.html