期货程序化交易CTP接口开发配套资源介绍
综合交易平台(Comprehensive Transaction Platform)简称CTP,是上海期货交易所为期货公司开发的一套期货经纪业务管理系统,由交易、风险控制和结算三大系统组成。
CTP接口支持股指期货、商品期货、商品期权等品种的交易,支持国内所有期货公司实盘的程序化交易。CTP系统能够同时连通国内四家期货交易所,支持国内商品期货和股指期货的交易结算业务。
CTP接口不仅是期货程序化交易的标准,同时他也影响了证券市场,比如华宝的LTS和中泰XTP都是借鉴了CTP接口的架构。
我们收集了一些CTP开发必要的资源,可以大大简化CTP开发工作,让大家尽快用CTP接口实现期货实盘程序化交易和量化交易。
CTP开发必要的资源有:
上海期货交易所官网 :
上期SIMNOW仿真账户: http://www.simnow.com.cn
Virtualapi (For CTP): http://www.virtualapi.cn
mdshare (历史行情数据下载适合Virtualapi回测使用):http://www.mdshare.cn
酷操盘手资管系统:http://www.kucs.com
而对于TradeAgent作为执行端(服务端)是有资金管理、虚拟仓统计功能、策略模式分组、策略统计曲线、列表功能是独立于API的功能,可以说非常强大有效。
Tradeapi支持交易,也支持资金查询回调,在Tradeagent端支持策略标号进行盈亏统计,下单方法支持虚拟仓(不接入实盘),可以说一套专业的程序化交易解决方案。
无论API和TrageAgent执行统计模块均由客户自行部署,我们作为产品提供方不做任何数据转发和功能执行。
支持的券商
TradeApi理论上支持所有券商,但因为券商繁多,我们目前提供了针对同花顺5.0~7.0的代理下单策略,总计支持70~80家券商,下方是支持的部分券商名单(完整券商名单请见:同花顺交易客户端相关->下载):
支持的编程语言
TradeApi Api支持多种编程语言,包括C++、Python、Java、C#、Golang、易语言等 。
支持的操作系统
TradeApi Api支持Windows操作系统,版本要求Windows8、Windows2012及以上。
C++代码窗口、资金查询窗口、持仓回调
下方为完整的C++ Demo1项目
下方为完整的C++ Demo1项目在Visual Studio2015下打开的截图,API封装方式为标志的CTP接口模式(上期CTP接口相当于行业标准,很多券商和服务商的行情和交易API都采用该模式)
支持6种资金查询,包括:资金余额、冻结资金、可用资金、可取资金、股票市值、总资产
通过回调函数返回资金查询结果
通过回调函数返回持仓查询结果
报单程序窗口和TradeAgent窗口
下图黑色的窗口为通过TradeApi的Api开发的自编程序向TradeAgent.exe进程(本机IP:127.0.0.1)进行报单, 由TradeAgent.exe并统计下单记录和资金曲线。
下单流程图
C++ 下单程序流程图
Python 下单程序流程图
代码
库文件说明
C++ 库文件
TradeApi提供的Api是C++库,理论上可以用于包括C++、Python、Java、C#、等在内的多种编程语言的调用。
TradeApi Api支持Windows操作系统,运行采用TradeApi Api的计算机和TradeAgent.exe的计算机采用要求Windows7、Windows2008及以上系统,并元要求对于Windwo7和Windows Server2008这些较为陈旧的Windows系统安装微软运行时库redist2015补丁。
包含以下文件:
其中ThostFtdcTradeApiDataType.h、ThostFtdcTradeApiStruct.h、ThostFtdcTraderApi.h是头文件,TradeApi.dll 动态库文件、TradeApi.lib。
Python 库文件
Python库是在原来C++ 库基础上增加了TradeApiForPython.dll和TradeApi.py,通过TradeApi.py采用ctypes方式调用 TradeApiForPython.dll 调用原生C++库中的 TradeApi.dll ,不再需要用户在开发过程中使用ThostFtdcTradeApiDataType.h、ThostFtdcTradeApiStruct.h、ThostFtdcTraderApi.h、TradeApi.lib这几个文件。
包含以下文件:
其中TradeApi.py是库文件、TradeApi.dll 是动态库文件、TradeApiForPython.dll 是动态库文件。
C++ Demo
C++ Demo采用Visual Studio2015、Visual Studio2017、Visual Studio2019 编译,运行test.sln打开Demo项目。
微软最新版本的Visual Studio下载: https://visualstudio.microsoft.com/zh-hans/downloads/
test.cpp
#include "stdafx.h"
#include "..\\..\\Library(C++)\\ThostFtdcTradeApiDataType.h"
#include "..\\..\\Library(C++)\\ThostFtdcTradeApiStruct.h"
#include "..\\..\\Library(C++)\\ThostFtdcTraderApi.h"
#include "TraderSpi.h"
CThostFtdcTraderApi *pTdApi;
CTraderSpi* pTdSpi;
#ifdef _WIN64
#pragma comment(lib, "..\\..\\Library(C++)\\x64\\TradeApi.lib")
#else
#pragma comment(lib, "..\\..\\Library(C++)\\x86\\TradeApi.lib")
#endif
char FRONT_ADDR[] = ""; // 前置地址
TThostFtdcBrokerIDType BROKER_ID = ""; // 经纪公司代码
TThostFtdcInvestorIDType INVESTOR_ID = ""; // 投资者代码
TThostFtdcPasswordType PASSWORD = ""; // 用户密码
int iInstrumentID = 1;
char *ppInstrumentID[] = {""};
double runtime = 0;
int iRequestID = 0;
bool usermssql = 0;
DWORD WINAPI GetQry(const LPVOID lpParam)
{
while (1)
{
//查询“资金余额” 在回调函数中返回
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_BALANCE);
Sleep(3000);
//查询“冻结的资金”
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_FROZENCASH);
Sleep(3000);
//查询“可用资金”
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_AVAILABLE);
Sleep(3000);
//查询“可取资金”
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_WITHDRAWQUOTA);
Sleep(3000);
//查询“股票市值”
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_STOCKVALUE);
Sleep(3000);
//查询“总资产”
pTdSpi->ReqQryTradingAccount(QRY_ACCOUNT_TOTAL);
Sleep(3000);
}
}
int main()
{
//TradeApi是A股交易接口
SYSTEMTIME st = { 0 };
GetLocalTime(&st);
runtime = 10000 * st.wYear + 100 * st.wMonth + st.wDay + 0.01*st.wHour + 0.0001*st.wMinute + 0.000001*st.wSecond
//因为在某些操作系统,例如某些最新版本的Windows10控制台,采用的编码为936,运行多字节会出现乱码,可以运行后设置,也可以运行下面命令直接切换至老式控制台编码
//若控制台乱码,请将needchcp改为1
bool needchcp =0;
if (needchcp)
{
system("chcp 20936");
}
cerr << "--->>> " << "Initialing TradeApi(www.tradeapi.cn 交易API库)Demo" << endl;
pTdApi = CThostFtdcTraderApi::CreateFtdcTraderApi(); // 创建交易
pTdSpi = new CTraderSpi();
//设置登录TradeAgent.exe进程服务的用户名和密码,账户密码配置见TradeAgent.exe目录下的setting.ini文件
pTdApi->SetLoginInfo("wdg", "000000wdg");
//设置交易参数,以便进行开仓数的计算和资金管理,100万资金,50%仓位,份10只股票买入,那么计算出每只股票使用50000元进行买入
//对股票最大开仓仓位30000股,如果不设置价格错误比如错误的价格数字1,GetCalOpenVolume(1),会导致一个极大的开仓数,导致潜在风险
//计算开仓数,请使用pTdApi->GetCalOpenVolume(10)方法进行计算,参数为价格10,50000/10元,即算出5000股
pTdApi->SetTradeParameters(1000000, 0.5, 10, 30000);
pTdApi->RegisterSpi(pTdSpi); // 注册事件类
pTdApi->RegisterFront("127.0.0.1"); // 连接交易服务器
pTdApi->Init();
int databasestate = 0;
//创建查询资金线程
HANDLE hThread2 = ::CreateThread(NULL, 0, GetQry, NULL, 0, NULL);
if (!usermssql)
{
//运行本程序需要安装Office2007及以上版本里的Access数据库模块,否则因为驱动程序无法顺利运行
//采用Access方式读取持仓数据,需要指定TradeApi Server的.mdb数据库地址,并在TradeApi Server启用Access数据库方式记录持仓信息
//pTdApi->InitAccess("..\\..\\TradeData.mdb");
databasestate = pTdApi->InitAccess("..\\..\\..\\TradeAgent(Server)\\TradeData.mdb");
}
else
{
//采用MSSQL方式读取持仓数据,需要指定MSSQL数据库地址,并在TradeApi Server启用MSSQL数据库方式记录持仓信息
databasestate = pTdApi->InitMSSQL("127.0.0.1", "TradeData", "user", "123456Test");
}
if (databasestate == 1)
{
//通过密码登录,输入正确的密码才能向TradeApi Server提交下单指令,用户名和密码在TraeeApi Server设置
pTdSpi->OnRspUserLogin("wdg", "000000wdg");
while (1)
{
//下单测试,买入卖出一个不存在的股票代码,仅供测试
//pTdSpi->ReqOrderInsert(1, "800000", pTdApi->GetCalOpenVolume(25.00), 25.00, DIRECTION_BUY);
//pTdSpi->ReqOrderInsert(1, "800000", 100, 25.00, DIRECTION_SELL);
pTdSpi->ReqOrderInsert(1, "800000", 100, 25, 25, DIRECTION_BUY, "显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等");
Sleep(10000);
pTdSpi->ReqOrderInsert(1, "800000", 100, 25, 25, DIRECTION_SELL,"显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等");
Sleep(10000);
}
}
return 1;
}
stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <windows.h>
#include <time.h>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#include <unordered_map>
#include <iostream>
#define DIRECTION_NONE 0
#define DIRECTION_BUY 1
#define DIRECTION_SELL 2
TraderSpi.h
#pragma once
#include "stdafx.h"
#include "..\\..\\Library(C++)\\ThostFtdcTraderApi.h"
class CTraderSpi : public CThostFtdcTraderSpi
{
public:
///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
virtual void OnFrontConnected();
///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
///@param nReason 错误原因
/// 0x1001 网络读失败
/// 0x1002 网络写失败
/// 0x2001 接收心跳超时
/// 0x2002 发送心跳失败
/// 0x2003 收到错误报文
virtual void OnFrontDisconnected(int nReason);
///登录请求响应
// virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) ;
virtual void OnRspUserLogin(char *username, char *password);
///登出请求响应
virtual void OnRspUserLogout(CThostFtdcTradeApiLogoutField *pUserLogout, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///错误应答
virtual void OnRspError(CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///报单录入请求响应
virtual void OnRspOrderInsert(COrderField *pInputOrder, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询投资者持仓响应
virtual void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
virtual void OnRtnOrder(CThostFtdcTradeOrderField *pOrder);
public:
///请求查询资金账户
void ReqQryTradingAccount();
///请求查询投资者持仓
void ReqQryInvestorPosition();
///报单录入请求
void ReqOrderInsert(int Sid, char *Instrument, int Volume, double Price, double LastPrice, int Direction, char *Remark);
///报单操作请求
void ReqOrderAction(CThostFtdcTradeOrderField *pOrder);
};
TraderSpi.cpp
#include
#include
#include
#include
using namespace std;
#include "stdafx.h"
#include "..\\..\\Library(C++)\\ThostFtdcTraderApi.h"
#include "TraderSpi.h"
#pragma warning(disable : 4996)
// USER_API参数
extern CThostFtdcTraderApi* pTdApi;
// 配置参数
extern char FRONT_ADDR[]; // 前置地址
extern char BROKER_ID[]; // 经纪公司代码
extern char INVESTOR_ID[]; // 投资者代码
extern char PASSWORD[]; // 用户密码
extern char* ppInstrumentID[];
extern int iInstrumentID;
extern char INSTRUMENT_ID[]; // 合约代码
extern TThostFtdcDirectionType DIRECTION; // 买卖方向
extern TThostFtdcOffsetFlagType MARKETState;//开平仓
extern TThostFtdcPriceType LIMIT_PRICE; // 价格
#define TYPE_NUM 20
extern double Q_UpperLimit;
extern double Q_LowerLimit;
extern bool JustRun; //正在启动标志
// 会话参数
TThostFtdcFrontIDType FRONT_ID; //前置编号
TThostFtdcSessionIDType SESSION_ID; //会话编号
TThostFtdcOrderRefType ORDER_REF; //报单引用
extern int needstate;
void CTraderSpi::OnFrontConnected()
{
cerr << "--->>> " << __FUNCTION__ << endl;
char username[51] = { 0 };
char password[51] = { 0 };
pTdApi->GetLoginInfoUsername(username);
pTdApi->GetLoginInfoPassword(password);
pTdApi->ReqUserLogin(username, password);
printf("[%s] are logging into the TradeAgent server...\n", username);
///用户登录请求
//ReqUserLogin();
Sleep(500);
}
void CTraderSpi::OnRspUserLogin(char *username, char *password)
{
cerr << "--->>> " << __FUNCTION__ << endl;
/*
if (pRspUserLogin == NULL)
{
cout << "--->>>指针错误OnRspUserLogin" << endl; //指针检查
//WirteTradeRecordToFileMainThread(0, "OnRspUserLogin指针错误");
Sleep(5000);
ReqUserLogin();// 自己添加
return;
}
if (IsErrorRspInfo(pRspInfo))
{
cerr << "--->>> 交易登录错误: " << pRspInfo->ErrorID << pRspInfo->ErrorMsg << endl;
//WirteTradeRecordToFileMainThread(0, "交易登录错误");
Sleep(5000);
ReqUserLogin();// 自己添加
}
if (bIsLast && !IsErrorRspInfo(pRspInfo))
{
// 保存会话参数
FRONT_ID = pRspUserLogin->FrontID;
SESSION_ID = pRspUserLogin->SessionID;
int iNextOrderRef = atoi(pRspUserLogin->MaxOrderRef);
iNextOrderRef++;
sprintf(ORDER_REF, "%d", iNextOrderRef);
//cerr << "--->>> 报单引用 = " << ORDER_REF << endl;
///获取当前交易日
char TradingDay[9] = { "0" };
strcpy(TradingDay, pTdApi->GetTradingDay());
cerr << "--->>> 获取当前交易日 = " << pTdApi->GetTradingDay() << endl;
}
*/
}
void CTraderSpi::OnRspUserLogout(CThostFtdcTradeApiLogoutField *pUserLogout, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
}
extern double YestayAllAmount;
extern double TodayAllAmount;
//extern double UserAmount;
int JsReqQryTradingAccountFailer = 0;
void CTraderSpi::ReqQryTradingAccount()
{
/*
CThostFtdcQryTradingAccountField req;
memset(&req, 0, sizeof(req));
strcpy(req.BrokerID, BROKER_ID);
strcpy(req.InvestorID, INVESTOR_ID);
int iResult = pTdApi->ReqQryTradingAccount(&req, ++iRequestID);
//cerr << "--->>> 请求查询资金账户: " << ((iResult == 0) ? "成功" : "失败") << endl;
if (iResult == 0)
{
JsReqQryTradingAccountFailer= 0;
}
else
{
JsReqQryTradingAccountFailer++;
if (JsReqQryTradingAccountFailer > 20)
{
printf("请求查询资金账户资金X失败");
}
}
*/
}
double UserAmount = 0;
void CTraderSpi::ReqQryInvestorPosition()
{
/*
CThostFtdcQryInvestorPositionField req;
memset(&req, 0, sizeof(req));
strcpy(req.BrokerID, BROKER_ID);
strcpy(req.InvestorID, INVESTOR_ID);
strcpy(req.InstrumentID, InstrumentID_n[0]);
int iResult = pTdApi->ReqQryInvestorPosition(&req, ++iRequestID);
//cerr << "--->>> 请求查询投资者持仓: " << ((iResult == 0) ? "成功" : "失败") << endl;
if (iResult == 0)
{
JsReqQryInvestorPositionFailer=0;
}
else
{
JsReqQryInvestorPositionFailer++;
if (JsReqQryInvestorPositionFailer > 20)
{
printf("请求查询投资者持仓X失败");
}
}
*/
}
bool FindStr(int id, char * str)
{
//char * pdest1 = strstr(InstrumentID_n[id], str);
//int result1 = pdest1 - InstrumentID_n[id] + 1;
//printf("%s %s\n", InstrumentID_n[id], str);
//if (stricmp(InstrumentID_n[id], str) == 0)
//if (pdest1 != NULL)
//{ //printf("在%s发现%s\n", InstrumentID_n[id],str );
return true;
//}
//else
//{
//printf("%s 没有在%s发现\n", str, InstrumentID_n[id]);
// return false;
//}
}
int SaveInstrumentID = { 0 };
bool checkstate = false;
bool TypeCheckState_B_Today[TYPE_NUM] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false };
bool TypeCheckState_S_Today[TYPE_NUM] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false };
bool TypeCheckState_B_History[TYPE_NUM] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false };
bool TypeCheckState_S_History[TYPE_NUM] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false };
int Trade_dataA_Amount_S_History[TYPE_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //空头持仓
int Trade_dataA_Amount_S_Today[TYPE_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //空头持仓
int Trade_dataA_Amount_B_History[TYPE_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //多头持仓
int Trade_dataA_Amount_B_Today[TYPE_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //多头持仓
//int Trade_dataA_Amount_B_Today = 0; //多头持仓
//int Trade_dataA_Amount_S_Today = 0; //多头持仓
bool orderstate = false;
///请求查询投资者持仓响应
void CTraderSpi::OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
}
extern int iRequestID;
extern int MAX_TRADENUM;
extern double totlemoney;
void CTraderSpi::ReqOrderInsert(int Sid, char *Instrument, int Volume, double Price, double LastPrice, int Direction, char *Remark)
{
COrderField req;
memset(&req, 0, sizeof(req));
req.Sid = Sid; //策略ID编号
strcpy(req.InstrumentID, Instrument); //股票代码
_snprintf_s(req.Remark, sizeof(req.Remark), sizeof(req.Remark) - 1, "%s", Remark); //备注,也可以输出策略程序的变量等
req.Volume = Volume; //下单数量
req.Price = Price; //委托价格
req.LastPrice = LastPrice; //委托价格
req.Direction = Direction; //买卖方向
int iRequestID = 1;
int iResult = pTdApi->ReqOrderInsert(&req, ++iRequestID);
cerr << "--->>> 报单录入请求: " << ((iResult == 0) ? "成功" : "失败") << endl;
}
void CTraderSpi::ReqOrderAction(CThostFtdcTradeOrderField *pOrder)
{
}
void CTraderSpi::OnRspOrderInsert(COrderField *pInputOrder, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
cerr << "--->>> " << __FUNCTION__ << endl;
SYSTEMTIME sys_time;
GetLocalTime(&sys_time);
double system_times;
system_times = (double)((sys_time.wHour) / 10e1) + (double)((sys_time.wMinute) / 10e3) + (double)((sys_time.wSecond) / 10e5); //格式时间0.145100
//cerr << "--->>> 报单: " <>> " << __FUNCTION__ << endl;
if (IsMyOrder(pOrder))
{
if (IsTradingOrder(pOrder))
ReqOrderAction(pOrder);
else if (pOrder->OrderStatus == THOST_FTDC_OST_Canceled)
cout << "--->>> 撤单成功" << endl;
}
}
void CTraderSpi::OnFrontDisconnected(int nReason)
{
cerr << "--->>> " << "OnFrontDisconnected" << endl;
cerr << "--->>> Reason = " << nReason << endl;
}
void CTraderSpi::OnRspError(CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
cerr << "--->>> " << "OnRspError" << endl;
IsErrorRspInfo(pRspInfo);
}
bool CTraderSpi::IsErrorRspInfo(CThostFtdcTradeApiRspInfoField *pRspInfo)
{
// 如果ErrorID != 0, 说明收到了错误的响应
bool bResult = ((pRspInfo) && (pRspInfo->ErrorID != 0));
if (bResult)
cerr << "--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << endl;
return bResult;
}
void CTraderSpi::ReqQryTradingAccount(int Cx)
{
cerr << "--->>> " << __FUNCTION__ << endl;
CThostFtdcQryTradingAccountField tn;
memset(&tn,0,sizeof(CThostFtdcQryTradingAccountField));
strcpy(tn.InvestorID,"000000");
int iResult = pTdApi->ReqQryTradingAccount(&tn, Cx);
}
void CTraderSpi::ReqQryInvestorPosition()
{
cerr << "--->>> " << __FUNCTION__ << endl;
}
Python Demo
Demo.py
#导入数据库代理
from TradeApi import *
import time, datetime
td = TradeApi()
# Direction or bsflag
DIRECTION_NONE = 0 # 不交易
DIRECTION_BUY = 1 # 买
DIRECTION_SELL = 2 # 卖
def main():
#初始化TradeApi交易库
td.InitTraderApi()
#向该IP的TradeAgent.exe进程报单,每个Python实例只能对1个TradeAgent.exe进程报单
td.RegisterFront("127.0.0.1")
#设定报单登录密码,错误将无法对TradeAgen.exe进程下单
#密码应在TradeAgent.exe设置
td.SetLoginInfo("wdg", "000000wdg")
#数据库主要用来记录持仓成本和计算各个策略的资金管理、统计各策略的盈亏曲线和胜率曲线
if True:
#Access数据库需要在运行TradeAgent.exe进程的主机上安装Office2007、Office2013、Office2016的Access模块
#对32位TradeAgent 32位程序请安装32位的Office(Access),对64位的TradeAgent 64位程序请安装64位的Office(Access)
#初始化Access数据库,采用Access查询持仓数据,需要指定Access文件路径
#Access数据库适合运行策略的系统,直接运行TradeAgent.exe下单程序
#1个策略或多个策略对应本机的1个TradeAgent.exe进程,对1个证券账户进行交易,数据库文件TradeData.mdb在TradeAgent.exe目录下
td.InitAccess("..\\..\\..\\TradeAgent(Server)\\TradeData2.mdb")
else:
#MSSQL数据库需要在运行TradeAgent.exe进程的主机上安装MSSQL,并导入TradeData.mdb到MSSQL,
#并配置管理器设置IP启用的地址断和数据库账户访问权限和密码
#初始化MSSQL数据库,采用MSSQL查询持仓数据,需要指定MSSQL网络连接方式
#MSSQL数据库适合运行策略的提交到多个账户交易的TradeAgent.exe系统
#1个策略或多个策略对应网络(物理主机或虚拟机)多个TradeAgent.exe进程,对多个证券账户进行交易,
#MSSQL数据库安装在运行TradeAgent.exe物理主机或虚拟机上
td.InitMSSQL("127.0.0.1","username","password")
while(1):
#下单测试,买入卖出一个不存在的股票代码,仅供测试
#td.ReqOrderInsert(1, "800000", pTdApi->GetCalOpenVolume(25.00), 25.00, DIRECTION_BUY);
#td.ReqOrderInsert(1, "800000", 100, 25.00, DIRECTION_SELL);
print(u"下单测试[买入]")
td.ReqOrderInsert(1, "800000", 100, 25, 25, DIRECTION_BUY, U"显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等")
time.sleep(10)
print(u"下单测试[卖出]")
td.ReqOrderInsert(1, "800000", 100, 25, 25, DIRECTION_SELL,U"显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等")
time.sleep(10)
if __name__ == '__main__':
main()
C++ 库提供的方法
以下是C++ 库头文件中提供并列出方法:
/////////////////////////////////////////////////////////////////////////
///@system TradeApi
///@file ThostFtdcTraderApi.h
///@brief 定义了客户端接口
///@history
///20190301 创建该文件
/////////////////////////////////////////////////////////////////////////
#if !defined(THOST_FTDCTRADERAPI_H)
#define THOST_FTDCTRADERAPI_H
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ThostFtdcTradeApiStruct.h"
#if defined(ISLIB) && defined(WIN32)
#ifdef LIB_TRADER_API_EXPORT
#define TRADER_API_EXPORT __declspec(dllexport)
#else
#define TRADER_API_EXPORT __declspec(dllimport)
#endif
#else
#define TRADER_API_EXPORT
#endif
class CThostFtdcTraderSpi
{
public:
///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
virtual void OnFrontConnected() {};
///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
///@param nReason 错误原因
/// 0x1001 网络读失败
/// 0x1002 网络写失败
/// 0x2001 接收心跳超时
/// 0x2002 发送心跳失败
/// 0x2003 收到错误报文
virtual void OnFrontDisconnected(int nReason) {};
///登录请求响应
//virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspUserLogin(char *username,char *password) {};
///登出请求响应
virtual void OnRspUserLogout(CThostFtdcTradeApiLogoutField *pUserLogout, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
///错误应答
virtual void OnRspError(CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
///报单录入请求响应
virtual void OnRspOrderInsert(COrderField *pInputOrder, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
///请求查询投资者持仓响应
virtual void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcTradeApiRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
///请求查询隔日监控的股票响应
virtual void OnRspQryMonitor(CMonitorField *pInputOrder) {};
virtual void OnRtnOrder(CThostFtdcTradeOrderField *pOrder) {};
};
class TRADER_API_EXPORT CThostFtdcTraderApi
{
public:
///创建TraderApi
///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录
///@return 创建出的UserApi
static CThostFtdcTraderApi *CreateFtdcTraderApi(const char *pszFlowPath = "", const bool bIsUsingUdp = false, const bool bIsMulticast = false);
///获取API的版本信息
///@retrun 获取到的版本号
static const char *GetApiVersion();
///删除接口对象本身
///@remark 不再使用本接口对象时,调用该函数删除接口对象
virtual void Release() = 0;
///初始化
///@remark 初始化运行环境,只有调用后,接口才开始工作
virtual void Init() = 0;
///获取当前交易日
///@retrun 获取到的交易日
///@remark 只有登录成功后,才能得到正确的交易日
virtual const char *GetTradingDay() = 0;
///注册前置机网络地址
///@param pszFrontAddress:前置机网络地址。
///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:17001”。
///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”17001”代表服务器端口号。
virtual void RegisterFront(char *pszFrontAddress) = 0;
///注册回调接口
///@param pSpi 派生自回调接口类的实例
virtual void RegisterSpi(CThostFtdcTraderSpi *pSpi) = 0;
///用户登录请求
virtual int ReqUserLogin(char *username, char *password) = 0;
///登出请求
virtual int ReqUserLogout(CThostFtdcTradeApiLogoutField *pUserLogout, int nRequestID) = 0;
///报单录入请求
///@param pInputOrder 报单信息
virtual int ReqOrderInsert(COrderField *pInputOrder, int nRequestID) = 0;
///设置API登录TradeAgent账户和密码,需要在TradeAgent.exe目录下的setting.ini中配置的一致,否则TradeAgent.exe无法接收下单指令
///@param username 账户
///@param password 密码
virtual void SetLoginInfo(char * Username, char *Password) = 0;
///获取根据SetLoginInfo设置的账户
///@param username 返回账户
virtual void GetLoginInfoUsername(char * Username) = 0;
///获取根据SetLoginInfo设置的密码
///@param username 返回账户
virtual void GetLoginInfoPassword(char * Password) = 0;
///设置交易参数
///@param useramount 账户资金总额
///@param positonrate 仓位比例
///@param number 分成几份购买股票,即购买股票数量
///购买每只股票的金额应该为 useramount*positonrate/number
///若购买number只股票一共占用positonrate的仓位
virtual void SetTradeParameters(double Useramount, double Positonrate,int StockNum,int Maxvol) = 0;
///读取交易参数
///@param useramount 账户资金总额
///@param positonrate 仓位比例
///@param number 分成几份购买股票,即购买股票数量
///返回值表示是否已经设置了交易参数,参数值存储在数据库的setting表里
virtual bool GetTradeParameters() = 0;
///读取交易参数
///@param useramount 账户资金总额
///@param positonrate 仓位比例
///@param number 分成几份购买股票,即购买股票数量
///返回值表示是否已经设置了交易参数,参数值存储在数据库的setting表里,并返回设置的值
virtual bool GetTradeParameters(double * Useramount, double * Positonrate, int * StockNum, int * Maxvol) = 0;
///根据SetTradeParameters设置的参数和价格来计算股票开仓手数
///@param Price 价格
virtual int GetCalOpenVolume(double Price) = 0;
///初始化MSSQL数据库,采用MSSQL查询持仓数据
///@param databaseaddress MSSQL数据库地址
///@param datasource 数据库名称
///@param username 数据库用户名
///@param password 数据库密码
virtual int InitMSSQL(char * databaseaddress, char *datasource, char * username, char * password) = 0;
///初始化Access数据库,采用Access查询持仓数据,需要指定Access文件路径
///@param path Access数据库文件路径,一般用于本机
virtual int InitAccess(char *path) = 0;
///设置Sid策略占用的总资金限额
///@param Sid 策略编号
virtual int SetAmount(int Sid, double AmountLimit) = 0;
///获得Sid策略可使用的剩余金额AmountLeft = 总资金限额AmountLimit -当前使用的
///@param Sid 策略编号
virtual double GetAmount(int Sid) = 0;
///获得股票合约代码可使用的剩余金额
///@param InstrumentID 股票合约代码
virtual double GetAmount(char * InstrumentID) = 0;
///获得股票合约代码可使用的剩余数量
///@param InstrumentID 股票合约代码
virtual int GetVolume(char * InstrumentID) = 0;
///查询所有股票合约持仓,来源下单代理软件数据库并非从券商账户查询,因为按涨停板价格下单购买就认为已经成交
///@param Instrument 股票合约代码
///@param sid 策略ID
///@param diffday 查询日期间隔大于diffday的持仓
//virtual int ReqDatabasePosition(char *InstrumentID, int Sid, int Diffday, int Direction) = 0;
///从MSSQL或Access数据库读取某一Sid的策略占用的资金占总资金比例,使用本方法前,需要执行InitMSSQL或InitAccess方法
///来源下单代理软件数据库并非从券商账户查询,因为按涨停板价格下单购买就认为已经成交
///@param sid 策略编号
///@param diffday 查询日期间隔大于diffday的持仓
virtual int RealtimeReadFromDatabaseInvestmentproportion(char *InstrumentID, int Sid, int Diffday, int Direction)=0;
///从MSSQL或Access数据库读取某一Sid的策略占用的资金数,使用本方法前,需要执行InitMSSQL或InitAccess方法
///来源下单代理软件数据库并非从券商账户查询,因为按涨停板价格下单购买就认为已经成交
///@param sid 策略编号
///@param diffday 查询日期间隔大于diffday的持仓
virtual int RealtimeReadFromDatabasePosition(char *InstrumentID, int Sid, int Diffday, int Direction) = 0;
///从MSSQL或Access数据库读取合约持仓股票数量,使用本方法前,需要执行InitMSSQL或InitAccess方法
///来源下单代理软件数据库并非从券商账户查询,因为按涨停板价格下单购买就认为已经成交
///@param InstrumentID 股票合约代码
///@param Sid 策略编号
///@param Diffday 查询日期间隔大于Diffday的持仓
///@param Direction 方向
virtual int RealtimeReadFromDatabaseVolume(char *InstrumentID, int Sid, int Diffday, int Direction) = 0;
///从MSSQL或Access数据库读取合约持仓股票数量,使用本方法前,需要执行InitMSSQL或InitAccess方法
///来源下单代理软件数据库并非从券商账户查询,因为按涨停板价格下单购买就认为已经成交
///@param InstrumentID 股票合约代码
///@param Sid 策略编号
///@param Direction 方向
virtual int RealtimeReadFromDatabaseGetBuyPosition(char *InstrumentID,int Sid, int Diffday, int Direction) = 0;
///从MSSQL或Access数据库读取股票持仓成本价,使用本方法前,需要执行InitMSSQL或InitAccess方法
///@param InstrumentID 股票合约代码
///@param Sid 策略编号
virtual double RealtimeReadFromDatabaseGetCostPrice(char *InstrumentID, int Sid) = 0;
///从MSSQL或Access数据库读取购买成交之后的日期,使用本方法前,需要执行InitMSSQL或InitAccess方法
///@param InstrumentID 股票合约代码
///@param Sid 策略编号
virtual int RealtimeReadFromDatabaseGetBuyDate(char *InstrumentID, int Sid) = 0;
///读取止盈或止损的记录信息
///@param InstrumentID 股票合约代码
///@param Sid 策略编号
///@param Type 止盈止损
///@param Price 触发价格
virtual double RealtimeReadFromDatabaseGetMonitor(char *InstrumentID, int Sid, int Type, double Price) = 0;
protected:
~CThostFtdcTraderApi() {};
};
#endif
Python 库提供的方法
Python库提供和C++库相同名称的方法
# -*- coding=utf-8 -*-
from ctypes import *
class TradeApi(object):
def __init__(self):
self.dll = CDLL('TradeApiForPython.dll')
self.fInitTraderApi = self.dll.InitTraderApi
self.fInitTraderApi.argtypes = []
self.fInitTraderApi.restype = c_void_p
self.fRegisterFront = self.dll.RegisterFront
self.fRegisterFront.argtypes = [c_char_p]
self.fRegisterFront.restype = c_void_p
self.fSetLoginInfo = self.dll.SetLoginInfo
self.fSetLoginInfo.argtypes = [c_char_p,c_char_p]
self.fSetLoginInfo.restype = c_void_p
self.fSetTradeParameters = self.dll.SetTradeParameters
self.fSetTradeParameters.argtypes = [c_double,c_double,c_int,c_int]
self.fSetTradeParameters.restype = c_void_p
self.fInitAccess = self.dll.InitAccess
self.fInitAccess.argtypes = [c_char_p]
self.fInitAccess.restype = c_void_p
self.fInitMSSQL = self.dll.InitMSSQL
self.fInitMSSQL.argtypes = [c_char_p,c_char_p,c_char_p,c_char_p]
self.fInitMSSQL.restype = c_void_p
self.fReqOrderInsert = self.dll.ReqOrderInsert
self.fReqOrderInsert.argtypes = [c_int,c_char_p,c_int,c_double,c_double,c_int,c_char_p]
self.fReqOrderInsert.restype = c_void_p
self.fSetAmount = self.dll.SetAmount
self.fSetAmount.argtypes = [c_int, c_double]
self.fSetAmount.restype = c_void_p
self.fGetAmount = self.dll.GetAmount
self.fGetAmount.argtypes = [c_int]
self.fGetAmount.restype = c_double
#取该股最后一次更新的数据
#def GetStockData(self,InstrumentID,tid):
# return self.fGetStockData(InstrumentID,tid)
#按时间先后顺序获取采集的TICK数据;每取一此数据,则从缓冲区删除该数据;
#如果长时间不取数据,为防止内存不断这家而溢出,则缓冲队列只保留最近的3万个
#def GetLastTick(self,InstrumentID,tid):
# return self.fGetLastTick(InstrumentID,tid)
#登录TradeAgent.exe进程的账户和密码,以保证交易指令确实是自己的策略进程发出
def InitTraderApi(self):
return self.fInitTraderApi()
#向该IP的TradeAgent.exe进程报单,每个Python实例只能对1个TradeAgent.exe进程报单
def RegisterFront(self,ip):
return self.fRegisterFront(ip)
#设定报单登录密码,错误将无法对TradeAgen.exe进程下单
#密码应在TradeAgent.exe设置
def SetLoginInfo(self,name,password):
return self.fSetLoginInfo(name,password)
#设置交易参数,以便进行开仓数的计算和资金管理,100万资金,50%仓位,份10只股票买入,那么计算出每只股票使用50000元进行买入
#对股票最大开仓仓位30000股,如果不设置价格错误比如错误的价格数字1,GetCalOpenVolume(1),会导致一个极大的开仓数,导致潜在风险
#计算开仓数,请使用pTdApi->GetCalOpenVolume(10)方法进行计算,参数为价格10,50000/10元,即算出5000股
#@param useramount 账户资金总额
#@param positonrate 仓位比例
#@param number 分成几份购买股票,即购买股票数量
#购买每只股票的金额应该为 useramount*positonrate/number
#若购买number只股票一共占用positonrate的仓位
def SetTradeParameters(self, Useramount, Positonrate, Number, Maxvol):
return self.fSetTradeParameters(Useramount, Positonrate, Number, Maxvol)
#初始化Access数据库,采用Access查询持仓数据,需要指定Access文件路径
#@param path Access数据库文件路径,一般用于本机
def InitAccess(self, path):
return self.fInitAccess(path)
#初始化MSSQL数据库,采用MSSQL查询持仓数据,需要指定MSSQL网络路径
#@param path Access数据库文件路径,一般用于本机
def InitMSSQL(self, ip, datasource, username, password):
return self.fInitMSSQL(ip, ip, datasource, username, password)
#报单录入请求
#@param Sid 策略编号
#@param Instrument 股票或合约代码
#@param Volume 下单量(手)
#@param Price 下单价格
#@param LastPrice 当前价格(用于TradeAge 计算统计盈亏成本)
#@param Direction 买卖方向
#@param Remark 备注(可在 TradeAge 显示策略变量的值)
def ReqOrderInsert(self, Sid, Instrument, Volume, Price, LastPrice, Direction, Remark):
return self.fReqOrderInsert( Sid, Instrument, Volume, Price, LastPrice, Direction, Remark)
#设置Sid策略占用的总资金限额
#@param Sid 策略编号
def SetAmount(self, Sid, AmountLimit):
return self.fSetAmount(Sid, AmountLimit)
#获得Sid策略可使用的剩余金额AmountLeft = 总资金限额AmountLimit -当前使用的
#@param Sid 策略编号
def GetAmount(self, Sid,):
return self.fGetAmount(Sid)
资金管理
功能介绍
TradeAgent.exe进程窗口如下图:
自带策略资金管理,仓位自动计算、方便管理多个策略各自持仓和盈亏统计 。
资金管理提供以下功能:
- 提供了方法可以查询各个策略的持仓;
- 对各个策略进行了平均盈亏,交易次数,胜率的统计;
- 支持自动禁用不盈利的策略;
- 支持策略收益曲线图;
- 支持人工设置策略模式,列入牛市模式,熊市模式。
多维度策略管理,自带多策略盈亏统计,自动淘汰策略, 全面的资金管理功能,有效降低开发成本。例如:
C++ 下单方法:
///报单录入请求
///@param Sid 策略编号
///@param Instrument 股票代码
///@param Volume 成交量
///@param Price 价格
///@param LastPrice 最新价(用于统计成本)
///@param Direction 交易方向(买、卖)
///@param Remark 备注(用于在TradeAgent进程窗口显示该笔交易的备注,可用于输出变量值)
void ReqOrderInsert(int Sid, char *Instrument, int Volume, double Price, double LastPrice, int Direction, char *Remark);
C++ 方法调用举例:
pTdSpi->ReqOrderInsert(1, "600000", 100, 25, 25, DIRECTION_BUY, "显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等");
Python 下单方法
td.ReqOrderInsert(1, "600000", 100, 25, 25, DIRECTION_BUY, U"显示在TradeAgent客户端的备注,可用于显示触发信号的变量值等")
策略收益曲线图
策略资金曲线图是在TradeAgent.exe程序中提供的,TradeAgent.exe作为服务器端接收TradeAgent的下单指令,同计算所有策略的收益曲线、盈亏曲线等,不仅提供了曲线图表,还提供多日累计列表方式显示。
双击列表中的一行,打开该记录周期的动态变化曲线
支持自动禁用不盈利的策略
支持自动禁用不盈利的策略
勾选:菜单->设置->自动禁用不盈利的策略
该功能在2.8及以后的版本开启。
人工设置策略模式
对于A股而言,由于牛市和熊市差别很大,所以如果能够认人为设定选择哪些策略进行交易,会更好的使得程交易策略更适合当前行情,获得更好的收益 。TradeApi的配套程序TradeAgent.exe 提供了人工设置策略模式的功能。
本功能在2.8以后的版本提供支持
同花顺交易客户端相关
下载
同花顺看盘软件图标 ,但这不是我们需要针对各个券商的同花顺交易客户端
同花顺交易客户端是同花顺公司根据各个券商封装的交易客户端,一般有2个渠道可以获得
- 1. 券商官网下载绿色版的同花顺交易客户端 http://download.10jqka.com.cn/
- 2.从同花顺官网下载的同花顺客户端安装后,从同花顺看盘软件菜单下载各个券商的绿色版交易软件,一般保存在C盘的目录下,可以复制出来独立运行。 打开同花顺看盘软件的菜单->委托开户->委托管理 打开下面的窗口,选择你需要的券商进行下载交易客户端软件,下载完毕一般在C盘,可拷贝出单独使用。
设置
目前支持同花顺5.0~同花顺7.0 的程序化交易下单,需要关闭同花顺的下单确认功能