功能:

1、开启之后,7*24自动运行。

2、在共享内存中存放当个交易日的tick数据,方便随时取用。

3、支持多行情源取数据。经过测试一个行情源峰值带宽要求为20M,所以使用时要配合带宽限制。

4、夜盘结束时输出一下tick数据,白盘结束时输出所有tick。

5、支持查询指令:

运行时如下:

贴上代码:

// FutureDataReceive.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "ThostFtdcMdSpiImpl.hpp"
#include "ThostFtdcTraderSpiImpl.hpp"
#include "future_helper.h"
#include "TinyConfig.h"
#include "FileMap.h"
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <conio.h> CFileMap g_fileMap;
TinyConfig g_config;
CThostFtdcTraderSpiImpl g_trade;
vector<shared_ptr<CThostFtdcMdSpiImpl>> g_vecQuote; int g_nPreTradingDay;
int g_nTradingDay;
bool g_bThread = true; boost::lockfree::queue<CThostFtdcDepthMarketDataField> g_buffer(1000);
shared_ptr<thread> g_thdDealData = nullptr;
vector<CThostFtdcDepthMarketDataField> g_vecBuffer; void OnLog(const char* p)
{
printf(p);
ofstream ofs_log("./log.data.receive.txt", ios_base::app);
ofs_log << future_helper::get_local_datetime().c_str() << " " << p;
ofs_log.close();
} #pragma region trade module
///trade call back
bool g_bTradeLoginIn = false;
void OnTradeComplete()
{
int nTradingDay = atoi(g_trade.GetTradingDay());
if (g_nTradingDay != 0 && g_nTradingDay != nTradingDay)
g_nPreTradingDay = g_nTradingDay; g_nTradingDay = nTradingDay;
g_bTradeLoginIn = true;
printf("交易日:%d-%d\n", g_nPreTradingDay, g_nTradingDay);
} void OnTradeRspMessage(const char* from, const char* msg, future_msg_type msg_type)
{
OnLog(future_helper::format_string("%s%s:%s\n", msg_type == future_msg_type::CTP_SUCCESS ? "" : "*", from, msg).c_str());
} void TradeLogin()
{
int retry_time = 3;
while (1)
{
g_bTradeLoginIn = false;
g_trade.SetCallBackFunc(OnTradeComplete, nullptr, OnTradeRspMessage);
g_trade.SetAuthenticate(g_config.GetValue("Trade", "product").c_str(), g_config.GetValue("Trade", "id").c_str(), g_config.GetValue("Trade", "code").c_str());
g_trade.InitParams(g_config.GetValue("Trade", "ip").c_str(), g_config.GetValue("Trade", "broker").c_str(),
g_config.GetValue("Trade", "user").c_str(), g_config.GetValue("Trade", "password").c_str()); int tick = GetTickCount();
while (1)
{
if (g_bTradeLoginIn) break;
this_thread::sleep_for(chrono::milliseconds(100));
if (GetTickCount() - tick > 60 * 1000) break;
} g_trade.Release();
g_fileMap.SetTradingDay(g_nPreTradingDay, g_nTradingDay);
if (g_bTradeLoginIn) break;
retry_time--;
OnLog("交易 登录超时[1分钟],重新登录\n");
if (retry_time == 0)
{
OnLog("交易 登录次数达到3次,不再尝试重新登录!\n");
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
#pragma endregion trade module ///market call back
int g_nMarketLoginIn = 0;
void OnMarketComplete()
{
g_nMarketLoginIn++;
} void OnMarketRspMessage(const char* from, const char* msg, future_msg_type msg_type)
{
OnLog(future_helper::format_string("%s%s:%s\n", msg_type == future_msg_type::CTP_SUCCESS ? "" : "*", from, msg).c_str());
} void OnDepthMarketData(CThostFtdcDepthMarketDataField* p)
{
if (!p) return;
g_buffer.push(*p);
} void MarketLogin()
{
int retry_time = 3;
std::vector<CThostFtdcInstrumentField> vecTradingCode;
g_trade.GetTradingCode(vecTradingCode, THOST_FTDC_PC_Futures);
g_trade.GetTradingCode(vecTradingCode, THOST_FTDC_PC_Options);
printf("订阅合约:%d\n", vecTradingCode.size());
g_fileMap.SetTradingCode(vecTradingCode);
while (1)
{
g_nMarketLoginIn = 0;
for (int i = 1; i <= 3; i++)
{
string this_ip = g_config.GetValue("Market", future_helper::format_string("ip%d", i).c_str());
if (this_ip == "") break;
auto pMdSpi = make_shared<CThostFtdcMdSpiImpl>();
g_vecQuote.push_back(pMdSpi);
pMdSpi->SetTradingCode(vecTradingCode);
pMdSpi->SetCallBackFunc(OnDepthMarketData, OnMarketRspMessage, nullptr, OnMarketComplete);
pMdSpi->InitParams(this_ip.c_str(), "8888", "88888888", "88888888");
} int tick = GetTickCount();
while (1)
{
if (g_nMarketLoginIn == g_vecQuote.size()) break;
this_thread::sleep_for(chrono::milliseconds(100));
if (GetTickCount() - tick > 60 * 1000) break;
} if (g_nMarketLoginIn > 0 && g_nMarketLoginIn != g_vecQuote.size())
{
int nUnconnectIndex = 1;
OnLog("***********************\n");
OnLog("*有未能正常登录的行情账号:\n");
for (auto iter = g_vecQuote.begin(); iter != g_vecQuote.end(); iter++)
{
if (!(*iter)->IsConnected())
{
OnLog(future_helper::format_string("%d、%s\n", nUnconnectIndex, (*iter)->GetFrontIP()).c_str());
nUnconnectIndex++;
}
}
OnLog("***********************\n");
OnLog("已有行情连接成功,未连接的不尝试重连\n");
} if (g_nMarketLoginIn > 0) break;
OnLog("行情 登录超时[1分钟],重新登录\n");
retry_time--;
if (retry_time == 0)
{
OnLog("行情 登录次数达到3次,不再尝试重新登录!\n");
break;
}
}
} void ThreadConsumeTick()
{
OnLog("处理线程已启动\n");
map<string, CThostFtdcDepthMarketDataField> m_mapShot;
while (g_bThread)
{
if (g_buffer.empty())
{
this_thread::sleep_for(chrono::milliseconds(5));
continue;
} CThostFtdcDepthMarketDataField data;
g_buffer.pop(data);
if (data.UpdateTime[2] == ':') {
data.UpdateTime[2] = data.UpdateTime[3];
data.UpdateTime[3] = data.UpdateTime[4];
data.UpdateTime[4] = data.UpdateTime[6];
data.UpdateTime[5] = data.UpdateTime[7];
data.UpdateTime[6] = 0;
} if (atoi(data.UpdateTime) > 180000) {
_snprintf_s(data.TradingDay, 9, "%d", g_nPreTradingDay);
}
else {
_snprintf_s(data.TradingDay, 9, "%d", g_nTradingDay);
} bool bNewTick = false;
auto find_shot = m_mapShot.find(data.InstrumentID);
if (find_shot == m_mapShot.end())
{
bNewTick = true;
m_mapShot[data.InstrumentID] = data;
}
else
{
long long llThis = future_helper::to_longlong(atoi(data.TradingDay), atoi(data.UpdateTime)) * 1000 + data.UpdateMillisec;
long long llLast = future_helper::to_longlong(atoi(find_shot->second.TradingDay), atoi(find_shot->second.UpdateTime)) * 1000 + find_shot->second.UpdateMillisec;
if (llThis > llLast || find_shot->second.Volume < data.Volume)
{//郑商所没有毫秒
bNewTick = true;
find_shot->second = data;
}
} if (bNewTick && g_fileMap.IsOK()) {
g_fileMap.AddDepthData(&data);
}
else if (bNewTick) {
g_vecBuffer.push_back(data);
}
}
OnLog("处理线程已退出\n");
} //bReset == true:清空共享内存中的tick数据
void OutPutTickData(bool bReset)
{
unsigned int* exist_size;
CThostFtdcDepthMarketDataField* p = g_fileMap.GetDepthData(&exist_size);
if (!p || *exist_size <= 0) {
OnLog("共享内存中无任何tick数据\n从内存中导出\n"); if (g_vecBuffer.size() == 0)
{
OnLog("内存中无任何tick数据\n");
return;
} future_helper::safe_create_floder((g_config.GetValue("Path", "tick_normal") + "\\" + future_helper::to_string(g_nTradingDay / 10000)).c_str());
ofstream ofs_tick(g_config.GetValue("Path", "tick_normal") + "\\" + future_helper::to_string(g_nTradingDay / 10000) +
"\\data_" + future_helper::to_string(g_nTradingDay) + ".txt", ios_base::out);
for (auto& field : g_vecBuffer)
{
char szBuf[1024];
_snprintf_s(szBuf, 1024,
//交易日,最后修改时间,最后修改毫秒,合约代码,
//最新价,上次结算价,昨收盘,昨持仓量,
//今开盘,最高价,最低价,数量,成交金额,持仓量,
//涨停板价,跌停板价,
//申买价一,申买量一,申卖价一,申卖量一,
//当日均价
"%s,%s,%d,%s,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%d,%.4f,%d,%.4f\n",
field.TradingDay, field.UpdateTime, field.UpdateMillisec, field.InstrumentID,
field.LastPrice, field.PreSettlementPrice, field.PreClosePrice, field.PreOpenInterest,
field.OpenPrice, field.HighestPrice, field.LowestPrice, field.Volume, field.Turnover, field.OpenInterest,
field.UpperLimitPrice, field.LowerLimitPrice,
field.BidPrice1, field.BidVolume1, field.AskPrice1, field.AskVolume1,
field.AveragePrice);
ofs_tick << szBuf;
}
return;
} OnLog(future_helper::format_string("输出共享内存中的tick数据 %d 个\n", *exist_size).c_str());
future_helper::safe_create_floder((g_config.GetValue("Path", "tick_normal") + "\\" + future_helper::to_string(g_nTradingDay / 10000)).c_str());
ofstream ofs_tick(g_config.GetValue("Path", "tick_normal") + "\\" + future_helper::to_string(g_nTradingDay / 10000) +
"\\data_" + future_helper::to_string(g_nTradingDay) + ".txt", ios_base::out);
for (int i = 0; i < *exist_size; i++)
{
auto& field = *(CThostFtdcDepthMarketDataField*)(p + i);
char szBuf[1024];
_snprintf_s(szBuf, 1024,
//交易日,最后修改时间,最后修改毫秒,合约代码,
//最新价,上次结算价,昨收盘,昨持仓量,
//今开盘,最高价,最低价,数量,成交金额,持仓量,
//涨停板价,跌停板价,
//申买价一,申买量一,申卖价一,申卖量一,
//当日均价
"%s,%s,%d,%s,%.3f,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%d,%.4f,%.4f,%.4f,%.4f,%.4f,%d,%.4f,%d,%.4f",
field.TradingDay, field.UpdateTime, field.UpdateMillisec, field.InstrumentID,
future_helper::check_double(field.LastPrice), future_helper::check_double(field.PreSettlementPrice), future_helper::check_double(field.PreClosePrice), future_helper::check_double(field.PreOpenInterest),
future_helper::check_double(field.OpenPrice), future_helper::check_double(field.HighestPrice), future_helper::check_double(field.LowestPrice), field.Volume, future_helper::check_double(field.Turnover), future_helper::check_double(field.OpenInterest),
future_helper::check_double(field.UpperLimitPrice), future_helper::check_double(field.LowerLimitPrice),
future_helper::check_double(field.BidPrice1), field.BidVolume1, future_helper::check_double(field.AskPrice1), field.AskVolume1,
future_helper::check_double(field.AveragePrice));
ofs_tick << szBuf << endl;
}
ofs_tick.flush();
ofs_tick.close(); if (bReset)
*exist_size = 0;
} void Open()
{
printf("%s\n", future_helper::get_local_datetime().c_str());
g_nMarketLoginIn = 0;
OnLog("区间交易开始!\n");
if (!g_thdDealData) {
g_bThread = true;
g_thdDealData = make_shared<thread>(ThreadConsumeTick);
} if (!g_fileMap.CreateFileMap(FILE_MAP_KEY))
{
OnLog("共享内存创建失败!直接存文件...\n");
}
else
{
g_fileMap.InitDefaultRange();
} TradeLogin();
unsigned int* exist_count;
auto pTick = g_fileMap.GetDepthData(&exist_count);
int local_time = atoi(future_helper::get_local_time(false).c_str());
if ((!pTick || *exist_count == 0) && (local_time < 151500 || local_time > 180000))
{
ifstream ifs_tick(g_config.GetValue("Path", "tick_normal") + "\\" + future_helper::to_string(g_nTradingDay / 10000) +
"\\data_" + future_helper::to_string(g_nTradingDay) + ".txt", ios_base::in);
if (ifs_tick.is_open())
{
OnLog("本地加载tick到共享内存:");
int tick_count = 0;
CThostFtdcDepthMarketDataField data;
char szLine[1024];
while (ifs_tick.getline(szLine, 1024))
{
future_helper::LineToStruct(szLine, data);
g_fileMap.AddDepthData(&data);
tick_count++;
}
OnLog(future_helper::format_string("%d条\n", tick_count).c_str());
}
}
MarketLogin();
} void Close()
{
printf("%s\n", future_helper::get_local_datetime().c_str());
int close_count = 0;
for (auto& md : g_vecQuote)
{
if (md->IsConnected()) {
close_count++;
md->ReleaseAPI();
}
}
g_vecQuote.clear();
if (close_count > 0) {
OnLog(future_helper::format_string("区间交易结束!关闭行情接收:%d\n", close_count).c_str());
if (g_thdDealData && g_thdDealData->joinable()) {
g_bThread = false;
g_thdDealData->join();
g_thdDealData = nullptr;
}
} g_nMarketLoginIn = 0;
OnLog(future_helper::format_string("共享内存使用%d/%d(mb)=%.2f%%%%\n",
g_fileMap.GetTotalUsedSpace() / 1024 / 1024, MAX_PAGE_SIZE / 1024 / 1024,
(double)g_fileMap.GetTotalUsedSpace() * 100 / MAX_PAGE_SIZE).c_str());
} int main()
{
if (!g_config.Open((future_helper::GetWorkingDir() + "\\system.ini").c_str()))
{
OnLog("system.ini打开失败\n");
system("pause");
} OnLog("执行开启共享内存测试...");
if (!g_fileMap.CreateFileMap(FILE_MAP_KEY))
{
OnLog("失败!");
system("pause");
}
else
{
OnLog("成功!\n");
g_fileMap.Release();
} OnLog("==========start==========\n"); printf("初次启动需要输入前交易日,用来更新夜盘的日期...");
scanf_s("%d", &g_nPreTradingDay);
int night_tick_count = -1;
int last_local_time = atoi(future_helper::get_local_time(false).c_str()); while (1)
{
if (_kbhit() != 0)
{
printf("**********不要长时间阻塞此处,这样将导致软件无法正常工作!***********\n");
printf("**********记得输入完之后按回车键哦! ***********\n");
string str;
std::getline(std::cin, str);
if (str == "quit")
{
Close();
break;
}
else if (str == "help")
{
printf("quit:退出\n");
printf("help:帮助\n");
printf("open:手动开启接收\n");
printf("close:手动关闭接收\n");
printf("tradingday:交易日\n");
printf("tradingcode:可交易合约\n");
printf("tickdata:输出接收到的tick数据\n");
printf("sharememory:共享内存使用率\n");
}
else if (str == "open")
{
Open();
}
else if (str == "close")
{
Close();
}
else if (str == "tradingday")
{
printf("交易日:%d-%d\n", g_nPreTradingDay, g_nTradingDay);
}
else if (str == "tradingcode")
{
printf("期货可交易合约:\n");
map<string, vector<CThostFtdcInstrumentField>> mapClasses;
vector<CThostFtdcInstrumentField> vec;
g_trade.GetTradingCode(vec, THOST_FTDC_PC_Futures);
for (auto& item : vec)
{
mapClasses[item.ProductID].push_back(item);
} for (auto iter = mapClasses.begin(); iter != mapClasses.end(); iter++)
{
printf("%s:", iter->first.c_str());
for (auto& item : iter->second)
{
printf("%s ", item.InstrumentID);
}
printf("\n");
}
}
else if (str == "tickdata")
{
OutPutTickData(false);
}
else if (str == "sharememory")
{
unsigned int* exist_size;
CThostFtdcDepthMarketDataField* p = g_fileMap.GetDepthData(&exist_size);
OnLog(future_helper::format_string("tick数据个数:%d\n共享内存使用%d/%d(mb)=%.2f%%%%\n",
p ? *exist_size : 0,
g_fileMap.GetTotalUsedSpace() / 1024 / 1024, MAX_PAGE_SIZE / 1024 / 1024,
(double)g_fileMap.GetTotalUsedSpace() * 100 / MAX_PAGE_SIZE).c_str());
}
} int local_time = atoi(future_helper::get_local_time(false).c_str());
if ((local_time >= 23500 && last_local_time < 23500) ||
(local_time >= 155000 && last_local_time < 155000))
{
unsigned int* exist_count;
auto pTick = g_fileMap.GetDepthData(&exist_count);
Close();
if ((local_time >= 155000 && last_local_time < 155000)){
OnLog("交易日结束了?...");
if (night_tick_count == -1 || *exist_count > night_tick_count) {
OnLog("是的!\n");
OutPutTickData(true);
if (night_tick_count != -1) {
OnLog("打开TickToKline.exe\n");
::ShellExecute(NULL, "open", (future_helper::GetWorkingDir() + "\\TickToKline.exe").c_str(), "1", NULL, SW_SHOW);
} night_tick_count = -1;
}
else
{
OnLog(future_helper::format_string("没有!(共享内存的数据没有比夜盘多%d-%d)!\n",
night_tick_count, *exist_count).c_str());
}
}
else
{
OnLog("夜盘结束了?...");
if (night_tick_count == -1 && *exist_count > 0) {
OnLog("是的!输出一次夜盘数据\n");
night_tick_count = *exist_count;
OutPutTickData(false);
}
else
{
OnLog("现在不是夜盘结束时间!(没有夜盘数据 或者 已经输出过一次夜盘数据了)\n");
}
}
}
if ((local_time >= 82000 && last_local_time < 82000) ||
(local_time >= 202000 && last_local_time < 202000))
{
Close();
Open();
} last_local_time = local_time;
this_thread::sleep_for(chrono::seconds(1));
} return 0;
}

  

欢迎讨论交流,qq896250188

期货、期权tick数据接收的更多相关文章

  1. 内核中用于数据接收的结构体struct msghdr(转)

    内核中用于数据接收的结构体struct msghdr(转) 我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构.在我们的虚拟机上发送icmp回显请求包,pin ...

  2. 酷友观点/经验:支付接口返回数据接收地址,session数据丢失(或者说失效)的问题浅析(原创文章)

    酷友观点/经验:支付接口返回数据接收地址,session数据丢失(或者说失效)的问题浅析(原创文章)   最近手头在开发一个游戏官网,在支付模块采用神州付技术支持,神州付数据表单中要求提供服务器返回地 ...

  3. stm32 usb数据接收与数据发送程序流程分析

    http://blog.csdn.net/u011318735/article/details/17424349 既然学习了USB,那就必须的搞懂USB设备与USB主机数据是怎么通讯的.这里主要讲设备 ...

  4. Spark Streaming 数据接收过程

    SparkStreaming 源码分析 一节中从源码角度,描述了Streaming执行时代码的调用过程.下边就接收转化阶段过程再简单分析一下,为分析backpressure作准备. SparkStre ...

  5. UDP数据接收服务器

    简介 这是我在做一个要用UDP方式进行数据传输时,自己写的一个多线程的UDP数据接收服务器, 它能将接收到的UDP数据包存成文件,并提供数据包接收时间监测: 还支持键盘命令响应,以将数据写到新的文件, ...

  6. 【ALB技术笔记】基于多线程方式的串行通信接口数据接收案例

    基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院  欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的 ...

  7. 【ALB学习笔记】基于事件触发方式的串行通信接口数据接收案例

    基于事件触发方式的串行通信接口数据接收案例 广东职业技术学院  欧浩源 一.案例背景 之前写过一篇<基于多线程方式的串行通信接口数据接收案例>的博文,讨论了采用轮询方式接收串口数据的情况. ...

  8. MVC查询数据接收及校验

    本来想写一篇aspx的TreeView控件绑值的文章的,在写案例的时候,写了一半,发现有些地方还得考虑以下,就留待下次了. 这一篇的话,是最近在开发一个项目的时候,有大量的页面和数据表,需要花式查询, ...

  9. udp协议的数据接收与发送的代码

    我想基于lwIP协议中的UDP协议,用单片机做一个服务器,接受电脑的指令然后返回数据.以下是我的代码 /************************************************ ...

随机推荐

  1. 永久破解pycharm,golang,IDEA开发工具

    1.去官网下载需要破解的IEDA 此处略去......... 2.需要破解的可以添加我微信获取破解jar包(百度网盘链接怕失效) 867716617 3.把jar包放在需要破解的IDEA安装目录中的l ...

  2. 5.Docker Compose 部署 Harbor

    什么是 Harbor Harbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器,通过添加一些企业必需的功能特性,例如安全.标识和管理等,扩展了开源 Docker Dis ...

  3. mysql 视图 触发器 存储过程 函数事务 索引

    mysql 视图 触发器 存储过程 函数事务 索引 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当 ...

  4. AOPS论坛上100+100个积分

    100+10 rare and irresistible integrals I bring you many beautiful integrals that I have collected ov ...

  5. LaTeX技巧012:LaTeX 插图加载宏包

    LaTeX 插图加载宏包.支持 LaTeX - DVIPDFMx; pdfLaTeX; XeLaTeX 三种编译方式,支持 eps/pdf/jpg/png 等图片格式. % Put this snip ...

  6. Linux常用命令: zip、unzip 压缩和解压缩命令

    zip基本用法是: zip [参数] [打包后的文件名] [打包的目录路径] 常用参数: -a 将文件转成ASCII模式 -F 尝试修复损坏的压缩文件 -h 显示帮助界面 -m 将文件压缩之后,删除源 ...

  7. numpy 一些知识

    import numpy as np 什么类型的相加,返回的还是什么类型的,所以在累加小类型的数值时会出现问题如下: a=np.array([123,232,221], dtype=np.uint8) ...

  8. MFC在子线程中创建窗口(PostMessage方法)

    1.创建子线程 C++创建线程的方式比较多 1)最简单易用的<thread>头文件,但是这种方法创建的子线程中无法给主线程PostMessage消息(也可能是我操作有误,总之没成功) 2) ...

  9. CallContext类

    CallContext类 转载weixin_30723433 最后发布于2019-07-20 10:42:24 阅读数 133  收藏 展开 System.Runtime.Remoting.Messa ...

  10. JDK8-》 ⽅法引⽤与构造函数引⽤

    以前⽅法调⽤ 对象.⽅法名 或者 类名.⽅法名 jdk1.8提供了另外⼀种调⽤⽅式 ::   说明:⽅法引⽤是⼀种更简洁易懂的lambda表达式,操作符是双冒号::,⽤来直接访问类或者实例 已经存在的 ...