功能:

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. ADO.NET中的数据库帮助类

    ADO.NET是.net framework中的一个重要模块,用于程序和数据源的连接,它的类都位于 System.Data.dll 中. 用于SQLServer的命名空间:System.Data.Sq ...

  2. Java架构师资料

    Java架构师ZHONGVIP课程资料链接   2017年第一学期的资料链接:(视频和文档是一起的) 一.互联网工程专题         链接:https://pan.baidu.com/s/1PGE ...

  3. 0级搭建类007-Ubuntu Desktop Linux安装 (18.04.2) 公开

    项目文档引子系列是根据项目原型,制作的测试实验文档,目的是为了提升项目过程中的实际动手能力,打造精品文档AskScuti. 项目文档引子系列目前不对外发布,仅作为博客记录.如学员在实际工作过程中需提前 ...

  4. IDEA常用的几个插件

    目录 1. 阿里巴巴代码检测插件 2. Json转Pojo插件 3. mybatis辅助插件 4. 翻译插件 5. markdown插件 6. RestfulToolKit插件 IDEA常用插件 1. ...

  5. unity一些操作汇总

    设置父物体高度自适应子物体:父物体添加ContentSizeFitter,设置Horizeontal Fit和Vertical Fit为Preferred Size. ScrollView设置Cone ...

  6. docker的个人理解

    一.什么是docker? docker就是集装箱的原理.可以实现远超于虚拟机的轻量级虚拟化.它是内核级的虚拟化.期望达到使项目运行环境一次封装,到处运行的目的. 集装箱解决了什么问题?在一艘大船上,可 ...

  7. hadoop 部署在centos 7 上

    一.准备工作  (文章写于 2019-6) 根据官方文档而来,请注意时间,官方可能有更新,以官方文档为准 1. 配置网站参考: http://hadoop.apache.org/docs/r1.0.4 ...

  8. 条件锁Condition

    """设计场景:timo先说一句,亚索再说一句timo: timo队长正在待命yasuo: 面对疾风吧timo: timo整装待发yasuo: 哈杀gay "& ...

  9. 162.扩展User模型-使用Proxy模型

    扩展用户模型: Django内置的User模型虽然已经足够强大了,但是有时候还是不能满足我们的需求,比如在验证用户登录的时候,它用的是用户名作为验证,而我们有时候需要通过手机号码或者是邮箱进行验证,还 ...

  10. AntDesign(React)学习-7 Menu添加事件

    今天花了大半天时间从老家回到工作地,路上因为肺炎封堵挺厉害,希望国家挺过这个难关,要不大家都失业可就惨了,上一篇做了一个展示数据的demo,这一篇研究antd Menu item点击事件 1.还是先看 ...