マーケット情報の受信処理
通貨ペア毎に最新レート情報をメモリに保持できるようにしときます
マーケット情報が「板情報」で来た場合は買値・売値の最適値のみをメモリに保持
他にもDBに履歴を保存しときます
< X > MarketDataIncrementalRefresh
#include "config.h"
#include "Application.h"
#include "quickfix/Session.h"
#include <iostream>
/* X */
void Application::onMessage(const FIX44::MarketDataIncrementalRefresh& message, const FIX::SessionID& sessionID )
{
/* INIT */
std::string id = "0";
std::string symbol = "";
unsigned long BidSize = 0;
double BidPx = 0.0;
unsigned int BidOrders = 0;
unsigned long OfferSize = 0;
double OfferPx = 0.0;
unsigned int OfferOrders = 0;
double Spred = 0.0;
/* メッセージ時刻取得 */
/* 52 */ FIX::FieldBase respDateTime(FIX::FIELD::SendingTime, "");
message.getHeader().getFieldIfSet(respDateTime);
/* グループレコード数取得 */
/* 268 */ FIX::FieldBase entries(FIX::FIELD::NoMDEntries, "0");
message.getFieldIfSet(entries);
/* 全レコードループ */
for(int i=1; i <= std::stoi(entries.getString()); i++)
{
/* レコード情報取得 */
/* 146 */ FIX44::MarketDataIncrementalRefresh::NoMDEntries e;
message.getGroup(i, e);
/* 初回のみ基本情報取得 */
if(i == 1)
{
/* アクションタイプ 0:New 2:Delete */
/* 279 */ FIX::FieldBase action(FIX::FIELD::MDUpdateAction, "0");
e.getFieldIfSet(action);
/* 通貨ペア */
/* 55 */ FIX::FieldBase symbol2(FIX::FIELD::Symbol, "NA");
e.getFieldIfSet(symbol2);
symbol = symbol2.getString();
/* 基本情報DB保存 */
std::ostringstream i1;
i1 << "insert into T_MARKET_DATA_HIST ( " <<
" `Symbol`, " <<
" `MDUpdateAction`, " <<
" `RespDateTime` " <<
" ) VALUES ( " <<
" '" << symbol << "', " <<
" '" << action << "', " <<
" '" << respDateTime << "' " <<
" )";
FIX::MySQLQuery q1( i1.str() );
if( m_sql->execute( q1 ) == true )
{
FIX::MySQLQuery q2("SELECT last_insert_id() FROM T_MARKET_DATA_HIST");
if( m_sql->execute( q2 ) == true )
{
id = q2.getValue(0,0);
LOG_VERBOSE << "INSERT T_MARKET_DATA_HIST id = " << id;
}
else
{
LOG_WARNING << "SELECT ERROR T_MARKET_DATA_HIST last_insert_id() :" << q2.reason() ;
}
}
else
{
LOG_WARNING << "INSERT ERROR T_MARKET_DATA_HIST :" << q1.reason() << std::endl << i1.str();
}
}
/* レコードタイプ取得 */
/* 269 */ FIX::FieldBase type(FIX::FIELD::MDEntryType, "0");
e.getFieldIfSet(type);
/* レート情報取得 */
/* 270 */ FIX::FieldBase px(FIX::FIELD::MDEntryPx, "0.0");
e.getFieldIfSet(px);
/* サイズ情報取得 */
/* 271 */ FIX::FieldBase size(FIX::FIELD::MDEntrySize, "0");
e.getFieldIfSet(size);
/* オーダー数情報取得 */
/* 346 */ FIX::FieldBase orders(FIX::FIELD::NumberOfOrders, "0");
e.getFieldIfSet(orders);
/* 詳細情報DB保存 */
std::ostringstream i3;
i3 << "insert into T_MARKET_DATA_DETAIL ( " <<
" `histId`, " <<
" `type`, " <<
" `px`, " <<
" `size`, " <<
" `orders` " <<
" ) VALUES ( " <<
" '" << id << "', " <<
" '" << type << "', " <<
" '" << px << "', " <<
" '" << size << "', " <<
" '" << orders << "' " <<
" )";
FIX::MySQLQuery q3( i3.str() );
if( m_sql->execute( q3 ) != true )
{
LOG_WARNING << "INSERT ERROR T_MARKET_DATA_DETAIL :" << q3.reason() << std::endl << i3.str();
}
else
{
LOG_VERBOSE << "INSERT T_MARKET_DATA_DETAIL : " << q3.reason() << std::endl << i3.str();
}
/* タイプ毎に値を取得調整 */
switch( *type.getString().c_str() )
{
case FIX::MDEntryType_BID:
/* 既存値より高い方を採用 */
if( BidPx < std::stod(px.getString() ))
{
BidPx = std::stod(px.getString());
BidSize = std::stoul(size.getString());
BidOrders = std::stoul(orders.getString());
}
break;
case FIX::MDEntryType_OFFER:
/* 既存値より安い方を採用 */
if( OfferPx == 0.0 || OfferPx > std::stod(px.getString() ))
{
OfferPx = std::stod(px.getString());
OfferSize = std::stoul(size.getString());
OfferOrders = std::stoul(orders.getString());
}
break;
case FIX::MDEntryType_TRADING_SESSION_VWAP_PRICE:
Spred = std::stod(px.getString());
break;
}
} /* 全レコードループ */
/* メモリ上のレート情報を更新 */
rate[m_symbol[symbol]].Time = respDateTime.getString();
rate[m_symbol[symbol]].feedStatus = true;
if( BidPx > 0.0 )
{
rate[m_symbol[symbol]].Bid = BidPx;
rate[m_symbol[symbol]].BidSize = BidSize;
rate[m_symbol[symbol]].BidOrder = BidOrders;
}
if( OfferPx > 0.0 )
{
rate[m_symbol[symbol]].Ask = OfferPx;
rate[m_symbol[symbol]].AskSize = OfferSize;
rate[m_symbol[symbol]].AskOrder = OfferOrders;
}
if( Spred > 0.0 )
{
rate[m_symbol[symbol]].Spred = Spred;
}
else
{
rate[m_symbol[symbol]].Spred = (double)(rate[m_symbol[symbol]].Ask - rate[m_symbol[symbol]].Bid);
}
/* DBのレート履歴を更新 */
std::ostringstream u4;
u4 <<
" `BidOrders` = " << rate[m_symbol[symbol]].BidOrder <<
" ,`BidSize` = " << rate[m_symbol[symbol]].BidSize <<
" ,`Bid` = " << rate[m_symbol[symbol]].Bid <<
" ,`Spred` = " << rate[m_symbol[symbol]].Spred <<
" ,`Offer` = " << rate[m_symbol[symbol]].Ask <<
" ,`OfferSize` = " << rate[m_symbol[symbol]].AskSize <<
" ,`OfferOrders` = " << rate[m_symbol[symbol]].AskOrder ;
std::string sql = "update T_MARKET_DATA_HIST SET "+ u4.str() +" where `id` = "+ id;
FIX::MySQLQuery q4( sql );
if( m_sql->execute( q4 ) != true )
{
LOG_WARNING << "UPDATE ERROR T_MARKET_DATA_HIST :" << q4.reason() << std::endl << sql;
}
else
{
LOG_VERBOSE << "UPDATE T_MARKET_DATA_HIST : " << q4.reason() << std::endl << sql;
}
/* DBの最新レートを更新 */
std::string u5 = "update T_MARKET_DATA SET `RespDateTime` = '"+
respDateTime.getString() +"', "+ u4.str() + " where `Symbol` = '"+ symbol +"'";
FIX::MySQLQuery q5( u5 );
if( m_sql->execute( q5 ) != true )
{
LOG_WARNING << "UPDATE ERROR T_MARKET_DATA :" << q5.reason() << std::endl << u5;
}
else
{
LOG_VERBOSE << "UPDATE T_MARKET_DATA : " << q5.reason() << std::endl << u5;
}
// std::cout << "<X> MarketDataIncrementalRefresh: " << std::endl << message.toXML() << std::endl;
LOG_VERBOSE << "<X> MarketDataIncrementalRefresh: " << std::endl << message;
//LOG_VERBOSE << "<X> MarketDataIncrementalRefresh: " << std::endl << message.toXML();
}
操作メニューに「最新レート情報表示」を追加
・・・
void Application::run()
{
while ( true )
{
try
{
std::string action;
std::cout << "------ " << YmdHMSs("%04d/%02d/%02d %02d:%02d:%02d.%03d" ) << " --------" << std::endl
<< "q) Quit" << std::endl
<< "r) Show rate " << std::endl
<< "Action: ";
std::cin >> action;
LOG_DEBUG << "COMMAND: " << action;
if ( action == "q" )
break;
else
if ( action == "r" )
{
for( auto symbol: m_symbol)
{
if(rate[symbol.second].feedStatus)
{
std::ostringstream s;
// s << std::fixed;
s << std::setprecision(8) ;
s << symbol.first << "\t"
<< rate[symbol.second].Time << " "
<< rate[symbol.second].Symbol << " "
<< rate[symbol.second].Bid << " \t"
<< rate[symbol.second].Spred << " \t"
<< rate[symbol.second].Ask << " "
<< std::endl;
std::cout << s << std::endl;
}
}
}
}
catch ( std::exception & e )
{
std::cout << "Message Not Sent: " << e.what();
LOG_WARNING << "Message Not Sent: " << e.what();
}
}
}
・・・
マーケット情報のサンプル
■Full Book, Non-Aggregated (未調整なので同じ値(270)が複数ある)
268=11
279=0 269=1 278=123 55=EUR/USD 270=1.3237 271=10000000
279=0 269=1 278=124 55=EUR/USD 270=1.3235 271=4300000
279=0 269=1 278=126 55=EUR/USD 270=1.3234 271=3000000
279=0 269=1 278=125 55=EUR/USD 270=1.3234 271=5000000
279=0 269=1 278=128 55=EUR/USD 270=1.3233 271=1000000
279=0 269=1 278=127 55=EUR/USD 270=1.3233 271=2000000
279=0 269=0 278=121 55=EUR/USD 270=1.3232 271=7000000
279=0 269=0 278=122 55=EUR/USD 270=1.3232 271=6500000
279=0 269=0 278=118 55=EUR/USD 270=1.3231 271=1000000
279=0 269=0 278=119 55=EUR/USD 270=1.3231 271=2000000
279=0 269=0 278=120 55=EUR/USD 270=1.3231 271=3000000
10=225
■Full Book Aggregated (調整されているAggregatedので 270に同じ値はない)
268=9
279=0 269=1 278=13 55=EUR/USD 270=1.32339 271=3000000 346=1
279=0 269=1 278=15 55=EUR/USD 270=1.32334 271=1000000 346=1
279=0 269=1 278=17 55=EUR/USD 270=1.32331 271=3000000 346=1
279=0 269=1 278=19 55=EUR/USD 270=1.32330 271=3000000 346=2
279=0 269=0 278=8 55=EUR/USD 270=1.32323 271=1000000 346=1
279=0 269=0 278=6 55=EUR/USD 270=1.32321 271=7000000 346=1
279=0 269=0 278=4 55=EUR/USD 270=1.32317 271=5000000 346=2
279=0 269=0 278=2 55=EUR/USD 270=1.32313 271=1000000 346=1
279=0 269=0 278=10 55=EUR/USD 270=1.32280 271=1000000 346=1
10=021
■Top of Book EUR/USD (最新値のみ)
268=2
279=0 269=1 278=2 55=EUR/USD 270=1.3233 271=1000000 346=1
279=0 269=0 278=1 55=EUR/USD 270=1.3231 271=7000000 346=1
10=182
DB内容のサンプル
mysql> select *
-> from T_MARKET_DATA;
+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+---------------------+------------+
| Symbol | RespDateTime | BidOrders | BidSize | Bid | Spred | Offer | OfferSize | OfferOrders | Created_at | Updated_at | Deleted_at |
+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+---------------------+------------+
| EUR/JPY | 20170424-15:04:50.272 | 1 | 1000000 | 119.451 | 0.7 | 119.458 | 2000000 | 1 | 2017-04-24 23:24:09 | 2017-04-25 00:04:50 | NULL |
| EUR/USD | 20170424-15:04:50.572 | 1 | 1000000 | 1.08629 | 0.5 | 1.08634 | 1300000 | 1 | 2017-04-24 23:24:09 | 2017-04-25 00:04:50 | NULL |
| USD/JPY | 20170424-15:04:49.609 | 1 | 2500000 | 109.957 | 0.1 | 109.958 | 2000000 | 1 | 2017-04-24 23:24:09 | 2017-04-25 00:04:49 | NULL |
+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+---------------------+------------+
3 rows in set (0.01 sec)
3つの通貨ペアについて、最新値が保存されとります
mysql> select *
-> from T_MARKET_DATA_DETAIL
-> limit 6900, 100;
+------+--------+------+---------+---------+--------+---------------------+
| id | histId | type | px | size | orders | Created_at |
+------+--------+------+---------+---------+--------+---------------------+
| 6901 | 1381 | 0 | 1.08629 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 6902 | 1381 | 1 | 1.08634 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 6903 | 1381 | 7 | 1.08726 | 0 | 0 | 2017-04-25 00:04:50 |
| 6904 | 1381 | 8 | 1.08437 | 0 | 0 | 2017-04-25 00:04:50 |
| 6905 | 1381 | 9 | 0.5 | 0 | 0 | 2017-04-25 00:04:50 |
| 6906 | 1382 | 0 | 119.451 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 6907 | 1382 | 1 | 119.457 | 4500000 | 1 | 2017-04-25 00:04:50 |
| 6908 | 1382 | 7 | 119.778 | 0 | 0 | 2017-04-25 00:04:50 |
| 6909 | 1382 | 8 | 119.347 | 0 | 0 | 2017-04-25 00:04:50 |
| 6910 | 1382 | 9 | 0.6 | 0 | 0 | 2017-04-25 00:04:50 |
| 6911 | 1383 | 0 | 119.451 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 6912 | 1383 | 1 | 119.458 | 2000000 | 1 | 2017-04-25 00:04:50 |
| 6913 | 1383 | 7 | 119.778 | 0 | 0 | 2017-04-25 00:04:50 |
| 6914 | 1383 | 8 | 119.347 | 0 | 0 | 2017-04-25 00:04:50 |
| 6915 | 1383 | 9 | 0.7 | 0 | 0 | 2017-04-25 00:04:50 |
| 6916 | 1384 | 0 | 1.08629 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 6917 | 1384 | 1 | 1.08634 | 1300000 | 1 | 2017-04-25 00:04:50 |
| 6918 | 1384 | 7 | 1.08726 | 0 | 0 | 2017-04-25 00:04:50 |
| 6919 | 1384 | 8 | 1.08437 | 0 | 0 | 2017-04-25 00:04:50 |
| 6920 | 1384 | 9 | 0.5 | 0 | 0 | 2017-04-25 00:04:50 |
+------+--------+------+---------+---------+--------+---------------------+
20 rows in set (0.01 sec)
受信している生データはこんな感じ
mysql> select *
-> from T_MARKET_DATA_HIST
-> limit 1350,100;
+------+----------------+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+
| id | MDUpdateAction | Symbol | RespDateTime | BidOrders | BidSize | Bid | Spred | Offer | OfferSize | OfferOrders | Created_at |
+------+----------------+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+
| 1351 | 0 | EUR/JPY | 20170424-15:04:42.265 | 1 | 1500000 | 119.448 | 0.6 | 119.454 | 1000000 | 1 | 2017-04-25 00:04:42 |
| 1352 | 0 | EUR/JPY | 20170424-15:04:42.762 | 1 | 500000 | 119.449 | 0.6 | 119.455 | 7500000 | 1 | 2017-04-25 00:04:43 |
| 1353 | 0 | EUR/JPY | 20170424-15:04:42.763 | 1 | 500000 | 119.449 | 0.6 | 119.455 | 4500000 | 1 | 2017-04-25 00:04:43 |
| 1354 | 0 | USD/JPY | 20170424-15:04:44.057 | 1 | 500000 | 109.958 | 0.1 | 109.959 | 1000000 | 1 | 2017-04-25 00:04:44 |
| 1355 | 0 | EUR/JPY | 20170424-15:04:44.256 | 2 | 3500000 | 119.448 | 0.6 | 119.454 | 1000000 | 1 | 2017-04-25 00:04:44 |
| 1356 | 0 | EUR/JPY | 20170424-15:04:44.256 | 1 | 2500000 | 119.448 | 0.6 | 119.454 | 1000000 | 1 | 2017-04-25 00:04:44 |
| 1357 | 0 | EUR/JPY | 20170424-15:04:44.257 | 1 | 1500000 | 119.448 | 0.6 | 119.454 | 1000000 | 1 | 2017-04-25 00:04:44 |
| 1358 | 0 | USD/JPY | 20170424-15:04:44.594 | 1 | 2500000 | 109.957 | 0.2 | 109.959 | 1000000 | 1 | 2017-04-25 00:04:45 |
| 1359 | 0 | EUR/USD | 20170424-15:04:44.599 | 1 | 4000000 | 1.0863 | 0.4 | 1.08634 | 3500000 | 1 | 2017-04-25 00:04:45 |
| 1360 | 0 | EUR/JPY | 20170424-15:04:44.772 | 1 | 500000 | 119.451 | 0.4 | 119.455 | 3500000 | 1 | 2017-04-25 00:04:45 |
| 1361 | 0 | EUR/JPY | 20170424-15:04:44.774 | 1 | 500000 | 119.451 | 0.6 | 119.457 | 3000000 | 1 | 2017-04-25 00:04:45 |
| 1362 | 0 | EUR/USD | 20170424-15:04:45.569 | 1 | 4000000 | 1.0863 | 0.3 | 1.08633 | 500000 | 1 | 2017-04-25 00:04:45 |
| 1363 | 0 | USD/JPY | 20170424-15:04:45.574 | 1 | 2500000 | 109.957 | 0.3 | 109.96 | 3000000 | 1 | 2017-04-25 00:04:45 |
| 1364 | 0 | USD/JPY | 20170424-15:04:45.574 | 1 | 2500000 | 109.957 | 0.3 | 109.96 | 1000000 | 1 | 2017-04-25 00:04:45 |
| 1365 | 0 | EUR/JPY | 20170424-15:04:45.760 | 1 | 500000 | 119.45 | 0.7 | 119.457 | 3000000 | 1 | 2017-04-25 00:04:45 |
| 1366 | 0 | USD/JPY | 20170424-15:04:46.067 | 1 | 2500000 | 109.957 | 0.2 | 109.959 | 1000000 | 1 | 2017-04-25 00:04:46 |
| 1367 | 0 | EUR/JPY | 20170424-15:04:46.259 | 1 | 2500000 | 119.449 | 0.8 | 119.457 | 4500000 | 1 | 2017-04-25 00:04:46 |
| 1368 | 0 | EUR/JPY | 20170424-15:04:46.260 | 1 | 1500000 | 119.449 | 0.8 | 119.457 | 4500000 | 1 | 2017-04-25 00:04:46 |
| 1369 | 0 | EUR/JPY | 20170424-15:04:46.756 | 1 | 500000 | 119.45 | 0.7 | 119.457 | 4500000 | 1 | 2017-04-25 00:04:46 |
| 1370 | 0 | EUR/USD | 20170424-15:04:47.063 | 1 | 4000000 | 1.0863 | 0.4 | 1.08634 | 500000 | 1 | 2017-04-25 00:04:47 |
| 1371 | 0 | EUR/JPY | 20170424-15:04:47.262 | 1 | 1000000 | 119.45 | 0.7 | 119.457 | 2000000 | 1 | 2017-04-25 00:04:47 |
| 1372 | 0 | EUR/JPY | 20170424-15:04:47.762 | 1 | 3000000 | 119.449 | 0.8 | 119.457 | 3000000 | 1 | 2017-04-25 00:04:47 |
| 1373 | 0 | EUR/JPY | 20170424-15:04:47.763 | 1 | 1500000 | 119.449 | 0.8 | 119.457 | 3000000 | 1 | 2017-04-25 00:04:47 |
| 1374 | 0 | EUR/USD | 20170424-15:04:48.119 | 1 | 4000000 | 1.0863 | 0.3 | 1.08633 | 500000 | 1 | 2017-04-25 00:04:48 |
| 1375 | 0 | EUR/JPY | 20170424-15:04:49.279 | 1 | 3000000 | 119.448 | 0.8 | 119.456 | 3000000 | 1 | 2017-04-25 00:04:49 |
| 1376 | 0 | EUR/JPY | 20170424-15:04:49.285 | 1 | 1500000 | 119.448 | 0.8 | 119.456 | 3000000 | 1 | 2017-04-25 00:04:49 |
| 1377 | 0 | USD/JPY | 20170424-15:04:49.609 | 1 | 2500000 | 109.957 | 0.1 | 109.958 | 2000000 | 1 | 2017-04-25 00:04:49 |
| 1378 | 0 | EUR/JPY | 20170424-15:04:49.771 | 1 | 2500000 | 119.447 | 0.9 | 119.456 | 2000000 | 1 | 2017-04-25 00:04:49 |
| 1379 | 0 | EUR/JPY | 20170424-15:04:49.774 | 1 | 1000000 | 119.448 | 0.8 | 119.456 | 2000000 | 1 | 2017-04-25 00:04:50 |
| 1380 | 0 | EUR/USD | 20170424-15:04:50.102 | 1 | 4000000 | 1.0863 | 0.4 | 1.08634 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 1381 | 0 | EUR/USD | 20170424-15:04:50.102 | 1 | 1000000 | 1.08629 | 0.5 | 1.08634 | 1000000 | 1 | 2017-04-25 00:04:50 |
| 1382 | 0 | EUR/JPY | 20170424-15:04:50.270 | 1 | 1000000 | 119.451 | 0.6 | 119.457 | 4500000 | 1 | 2017-04-25 00:04:50 |
| 1383 | 0 | EUR/JPY | 20170424-15:04:50.272 | 1 | 1000000 | 119.451 | 0.7 | 119.458 | 2000000 | 1 | 2017-04-25 00:04:50 |
| 1384 | 0 | EUR/USD | 20170424-15:04:50.572 | 1 | 1000000 | 1.08629 | 0.5 | 1.08634 | 1300000 | 1 | 2017-04-25 00:04:50 |
+------+----------------+---------+-----------------------+-----------+---------+---------+-------+---------+-----------+-------------+---------------------+
34 rows in set (0.01 sec)
<前 【QuickFIX】12 マーケット情報要求 < V > MarketDataRequest
次> 【QuickFIX】14 口座情報要求 < AN > RequestForPositions
一覧
01 サンプルのコンパイル
02 ログイン時にPassword(554)を送信
03 送受信ログをMySQLに保存
04 情報保存用にMySQLコネクションを保持..他
05 各種メッセージの枠を作成
06 独自メッセージ仕様
07 セッション開始 TradingSessionStatus
08 通貨ペア要求 SecurityListRequest
09 通貨ペア取得 SecurityList
10 デモ環境サーバへ接続
11 ログ出力設定
12 マーケット情報要求 < V > MarketDataRequest
13 マーケット情報受信 < X > MarketDataIncrementalRefresh
14 口座情報要求 < AN > RequestForPositions
15 口座情報取得 < AZ > CollateralResponse