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

＜前 [【QuickFIX】03 送受信ログをMySQLに保存](https://qiita.com/nobu-maple/items/cc943f0c1028f21161c0)
次＞ [【QuickFIX】05 各種メッセージの枠を作成](https://qiita.com/nobu-maple/items/770d8da8c50c4f5a5a54)


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

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


##Applicationヘッダーファイル
```c++: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ソースファイル
```c++: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 
```


##設定ファイルに項目追加
```bash: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確認
```sql
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に保存](https://qiita.com/nobu-maple/items/cc943f0c1028f21161c0)
次＞ [【QuickFIX】05 各種メッセージの枠を作成](https://qiita.com/nobu-maple/items/770d8da8c50c4f5a5a54)


---
# 一覧
[01 サンプルのコンパイル](https://qiita.com/nobu-maple/items/051188f21efc59429808)
[02 ログイン時にPassword(554)を送信](https://qiita.com/nobu-maple/items/649f1fd2525523f12064)
[03 送受信ログをMySQLに保存](https://qiita.com/nobu-maple/items/cc943f0c1028f21161c0)
[04 情報保存用にMySQLコネクションを保持..他](https://qiita.com/nobu-maple/items/cfe505ad984e16d46af9)
[05 各種メッセージの枠を作成](https://qiita.com/nobu-maple/items/770d8da8c50c4f5a5a54)
[06 独自メッセージ仕様](https://qiita.com/nobu-maple/items/580815f3c304d96bde31)
[07 セッション開始 <h> TradingSessionStatus](https://qiita.com/nobu-maple/items/98369bad8351cb662740)
[08 通貨ペア要求 <x> SecurityListRequest](https://qiita.com/nobu-maple/items/ba0fb7175c378bc4c608)
[09 通貨ペア取得 <y> SecurityList](https://qiita.com/nobu-maple/items/66feda02d9a717bd31b9)
[10 デモ環境サーバへ接続](https://qiita.com/nobu-maple/items/52de92892a03f59c7368)
[11 ログ出力設定](https://qiita.com/nobu-maple/items/828d3859ebf2ab2237f8)
[12 マーケット情報要求 < V > MarketDataRequest](https://qiita.com/nobu-maple/items/1c4f2d27cabde8eff713)
[13 マーケット情報受信 < X > MarketDataIncrementalRefresh](https://qiita.com/nobu-maple/items/eb7855841000eb2b0f04)
[14 口座情報要求 < AN > RequestForPositions](https://qiita.com/nobu-maple/items/30c286f8dbf1e9b0e173)
[15 口座情報取得 < AZ > CollateralResponse](https://qiita.com/nobu-maple/items/a16e3c787ef5e83f3971)

---