0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【QuickFIX】04 情報保存用にMySQLコネクションを保持..他

Last updated at Posted at 2017-04-15

<前 【QuickFIX】03 送受信ログをMySQLに保存
次> 【QuickFIX】05 各種メッセージの枠を作成

取引情報やレート情報を保存するためのMySQLコネクションを保持できるようにしときます。

その他もろもろ?設定とかごみ削除とか

##Applicationヘッダーファイル

Application.h
        #ifndef TRADECLIENT_APPLICATION_H
        #define TRADECLIENT_APPLICATION_H

        #include "quickfix/Application.h"
        #include "quickfix/MessageCracker.h"
        #include "quickfix/Values.h"
        #include "quickfix/Mutex.h"

      #include "quickfix/MySQLConnection.h"

        #include <queue>
      #include <vector>
      #include <map>

      const char SessionTypeTrade [] = "Trade";
      const char SessionTypeRatefeed [] = "Ratefeed";
      const char AppDEFAULT_DATABASE[] = "quickfix";
      const char AppDEFAULT_USER[] = "root";
      const char AppDEFAULT_PASS[] = "";
      const char AppDEFAULT_HOST[] = "localhost";
      const short AppDEFAULT_PORT = 3306;

        class Application :
              public FIX::Application,
              public FIX::MessageCracker
        {
        public:
          Application( const FIX::SessionSettings& settings )
            : m_settings( settings )
        {
          m_sql = MySQLConnect();
          m_accountID = getSetting("AccountID");
          m_partyID = getSetting("PartyID");
          m_tradeSessionStatus = false;
          m_ratefeedSessionStatus = false;
        }

        ~Application()
        {
          if (m_sql) delete m_sql;
        }

          void run();

        private:
          FIX::SessionSettings m_settings;
        FIX::MySQLConnection *m_sql;
        std::string m_database;
        std::string m_user;
        std::string m_pass;
        std::string m_host;
        short m_port;
        bool m_tradeSessionStatus;
        bool m_ratefeedSessionStatus;
        std::map<std::string, std::string> m_senderID;
        std::map<std::string, std::string> m_targetID;
        std::string m_accountID;
        std::string m_partyID;

          void onCreate( const FIX::SessionID& ) {}
          void onLogon( const FIX::SessionID& sessionID );
          void onLogout( const FIX::SessionID& sessionID );
          void toAdmin( FIX::Message&, const FIX::SessionID& );
          void toApp( FIX::Message&, const FIX::SessionID& )
          throw( FIX::DoNotSend );
          void fromAdmin( const FIX::Message&, const FIX::SessionID& )
          throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon ) {}
          void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
          throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType );

        void SetMessageHeader( FIX::Message&, const char* = SessionTypeTrade );
        FIX::MySQLConnection *MySQLConnect();
        std::string getSetting( const char* );
        std::string YmdHMSs( const char* = "%04d%02d%02d-%02d%02d%02d.%03d" );

        };

        #endif

##Applicationソースファイル

Application.cpp
        #include "config.h"

        #include "Application.h"
        #include "quickfix/Session.h"
        #include <iostream>

        void Application::onLogon( const FIX::SessionID& sessionID )
        {
          std::cout << std::endl << "Logon - " << sessionID << std::endl;
        }

        void Application::onLogout( const FIX::SessionID& sessionID )
        {
          std::cout << std::endl << "Logout - " << sessionID << std::endl;
        }

        void Application::fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
        throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
        {
          crack( message, sessionID );
          std::cout << std::endl << "IN: " << message << std::endl;
        }

        void Application::toAdmin( FIX::Message& message, const FIX::SessionID& sessionID )
        {
          if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
          {
            const FIX::Dictionary& dic = m_settings.get( sessionID );
            if (dic.has("Password"))
              message.getHeader().setField(FIX::Password(dic.getString("Password")));
          }
        }

        void Application::toApp( FIX::Message& message, const FIX::SessionID& sessionID )
        throw( FIX::DoNotSend )
        {
          try
          {
            FIX::PossDupFlag possDupFlag;
            message.getHeader().getField( possDupFlag );
            if ( possDupFlag ) throw FIX::DoNotSend();
          }
          catch ( FIX::FieldNotFound& ) {}

          std::cout << std::endl
          << "OUT: " << message << std::endl;
        }

        void Application::run()
        {
          while ( true )
          {
            try
            {
              std::string action;
            std::cout << "------ " << YmdHMSs("%04d/%02d/%02d %02d:%02d:%02d.%03d" ) << " --------" << std::endl
                << "quit) Quit" << std::endl
                << "Action: ";
              std::cin >> action;

              if ( action == "quit" )
                break;
            }
            catch ( std::exception & e )
            {
              std::cout << "Message Not Sent: " << e.what();
            }
          }
        }


      void Application::SetMessageHeader( FIX::Message& message, const char* sessionType )
      {
        auto itr = m_senderID.find(sessionType);
        if (itr == m_senderID.end())
        {
          const std::set <FIX::SessionID> session = m_settings.getSessions();
          for (std::set <FIX::SessionID>::iterator it = session.begin(); it != session.end(); ++it)
          {
            const FIX::Dictionary dic = m_settings.get( *it );
            if (dic.getString("SessionType") == sessionType)
            {
              m_senderID[dic.getString("SessionType")] = dic.getString("SenderCompID");
              m_targetID[dic.getString("SessionType")] = dic.getString("TargetCompID");
              break;
            }
          }
        }
        message.getHeader().setField((FIX::SenderCompID)m_senderID[sessionType]);
        message.getHeader().setField((FIX::TargetCompID)m_targetID[sessionType]);
      }

      FIX::MySQLConnection *Application::MySQLConnect()
      {
        if (m_database == "")
        {
          m_database = AppDEFAULT_DATABASE;
          m_user = AppDEFAULT_USER;
          m_pass = AppDEFAULT_PASS;
          m_host = AppDEFAULT_HOST;
          m_port = AppDEFAULT_PORT;
           const FIX::Dictionary dic = m_settings.get();
          if (dic.has("MySQLStoreDatabase")) m_database = dic.getString("MySQLStoreDatabase");
          if (dic.has("MySQLStoreUser")) m_user = dic.getString("MySQLStoreUser");
          if (dic.has("MySQLStorePassword")) m_pass = dic.getString("MySQLStorePassword");
          if (dic.has("MySQLStoreHost")) m_host = dic.getString("MySQLStoreHost");
          if (dic.has("MySQLStorePort")) m_port = dic.getInt("MySQLStorePort");
        }
         return new FIX::MySQLConnection( m_database, m_user, m_pass, m_host, m_port );
      }

      std::string Application::getSetting( const char* key )
      {
        const FIX::Dictionary dic = m_settings.get();
        if (dic.has(key)) return dic.getString(key);
        return key;
      }

      std::string Application::YmdHMSs( const char* format )
      {
        FIX::UtcTimeStamp time;
        int year, month, day, hour, minute, second, millis;
        time.getYMD( year, month, day );
        time.getHMS( hour, minute, second, millis );
        char tm[ 30 ];
        // YYYYmmdd-HHMMSS.sss "%04d%02d%02d-%02d%02d%02d.%03d"
        // 1234567890123456789
        STRING_SPRINTF( tm, format, year, month, day, hour, minute, second, millis );
        return tm;
      }

##コンパイル

tradeclient]$ make clean
tradeclient]$ make 

##設定ファイルに項目追加

tradeclient.cfg
[DEFAULT]
ConnectionType=initiator
ReconnectInterval=60
FileStorePath=store
FileLogPath=log
StartTime=00:00:00
EndTime=00:00:00
UseDataDictionary=Y
DataDictionary=FIX44.xml
HttpAcceptPort=9911

ValidateUserDefinedFields=N
ResetOnLogout=Y
ResetOnLogon=Y

# -- MySQL Store ----
MySQLStoreDatabase=Quick
MySQLStoreUser=QuickUSER
MySQLStorePassword=QuickPASS
MySQLStoreHost=localhost

# -- MySQL Log ------
MySQLLogDatabase=Quick
MySQLLogUser=QuickUSER
MySQLLogPassword=QuickPASS
MySQLLogHost=localhost

# -- Account ------
AccountID=CAXDemo_Account
PartyID=CAXDemo_Account

[SESSION]
BeginString=FIX.4.4
SenderCompID=CAXDemo_Account_Trd
TargetCompID=CNX
SocketConnectHost=127.0.0.1
SocketConnectPort=9999
HeartBtInt=30
Password=Pass1234
SessionType=Trade

[SESSION]
BeginString=FIX.4.4
SenderCompID=CAXDemo_Account_Str
TargetCompID=CNX
SocketConnectHost=127.0.0.1
SocketConnectPort=9999
HeartBtInt=30
Password=Pass1234
SessionType=Ratefeed

###動作確認

tradeclient]$ ./tradeclient  tradeclient.cfg
------ 2017/04/12 04:49:53.866 --------
quit) Quit
Action:
Logout - FIX.4.4:CAXDemo_Account_Str->CNX

Logout - FIX.4.4:CAXDemo_Account_Trd->CNX

quit
tradeclient]$

ちゃんと動いてます。ね。

DB確認

tradeclient]$ mysql -u QuickUSER -p Quick

select sendercompid
     , targetcompid
     , replace(message,char(1),' ') as 'message'
  from messages
;
+---------------------+--------------+------------------------------------------------------------------------------------------------------------------------+
| sendercompid        | targetcompid | message                                                                                                                |
+---------------------+--------------+------------------------------------------------------------------------------------------------------------------------+
| CAXDemo_Account_Str | CNX          | 8=FIX.4.4 9=96 35=A 34=1 49=CAXDemo_Account_Str 52=20170412-04:49:53.943 56=CNX 554=Pass1234 98=0 108=30 141=Y 10=135  |
| CAXDemo_Account_Trd | CNX          | 8=FIX.4.4 9=96 35=A 34=1 49=CAXDemo_Account_Trd 52=20170412-04:49:54.046 56=CNX 554=Pass1234 98=0 108=30 141=Y 10=115  |
+---------------------+--------------+------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)


DBにもちゃんと保存されてる

<前 【QuickFIX】03 送受信ログをMySQLに保存
次> 【QuickFIX】05 各種メッセージの枠を作成


一覧

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


0
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?