06
--
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
--
>>
<<
--
LATEST ENTRY
CATEGORY
ARCHIVE
PROFILE
SEARCH
RECENT COMMENT
  • 【情報】Excel で スクレイピング 【ぶっこ抜き】
    縫部尚登 (06/17)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/05)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    まこ (05/05)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/04)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/04)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/04)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/03)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    まこ (05/03)
  • 【QUICKFIX】 FX自動売買への道 18 【通貨ペアの取得(SecurityListRequest)】
    ganponfx (05/03)
  • エクセルファイルのパスワードを忘れたら・・・
    里奈 (09/09)
MOBILE
qrcode
OTHERS
<< 【QUICKFIX】 FX自動売買への道 13 【Application.cpp の分割】 | top | 【QUICKFIX】 FX自動売買への道 15 【受信メッセージをとりあえず受ける口を作る】 >>
スポンサーサイト

一定期間更新がないため広告を表示しています

スポンサードリンク | - | | - | - |
【QUICKFIX】 FX自動売買への道 14 【独自テーブルへのINSERT&SELECT】
Application.cpp からレート情報やらポジション情報やらを
DBに保存したり読み出したりするためのDB接続操作関連の機能を追加しときます。



 

基本的には QuickFIX に既にある機能をそのまま使わせてもらいます。

今後取引に関する情報やら各種ログやら色んな情報をDBへ保存したり
読み出したりする予定ですが、DBに接続できないとかSQLエラーとかのトラブルが
発生した場合にはDBではなく syslog に情報を吐き出しとく仕組みも組み込んどきます。
DB接続エラーのログをDBには保存できないですしね。。


■まずはヘッダーファイルの編集(Application.h)
tradeclient]# vi Application.h
ーー全文ーーーーーーーーーーーーーーーーーーーーーー
        #ifndef TRADECLIENT_APPLICATION_H
        #define TRADECLIENT_APPLICATION_H

        #include "quickfix/Application.h"
        #include "quickfix/MessageCracker.h"
     #include "quickfix/MySQLConnection.h"
     #include "quickfix/MySQLStore.h"

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

        #include "quickfix/fix44/TestRequest.h"                     // < 1 >
        #include "quickfix/fix44/TradingSessionStatus.h"            // < h >

        #include <queue>
     #include <syslog.h>

        const char SessionTypeTrade[] = "Trade";
        const char SessionTypeRatefeed[] = "Ratefeed";

        class Application :
              public FIX::Application,
              public FIX::MessageCracker
        {
        public:
          Application( const FIX::SessionSettings& settings )
          : m_settings( settings )
       { openlog("QuickFIX", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
         MySQLConnect();
          }


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


          void run();

        private:
          FIX::SessionSettings m_settings;
       FIX::MySQLConnection *m_sql;

          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 );

          /* h  */ void onMessage( const FIX44::TradingSessionStatus&, const FIX::SessionID& );

          /* 1  */ void TestRequest(const char* );
       /* 1  */ void InsertTestRequest( const FIX::Message& );

          void SetMessageHeader( FIX::Message&, const char* );

       void MySQLConnect();
       FIX::MySQLQuery MySQLExec( const std::string& );

       std::string YmdHMSs();


        };

        #endif

ーーーーーーーーーーーーーーーーーーーーーーーー
 MySQLを利用するためのヘッダー取り込み
◆DB関連で何かあった時のために、syslog 利用できるようにしときます
 Application の初期設定時に MySQLへのコネクションを張っときます
ぁApplication の破棄処理時に MySQL へのコネクションを破棄しときます
ァMySQL へのコネクション保存用
ΑTestRequestの際にメッセージ内容をDBへInsertする関数を宣言
АMySQL へのコネクションを行う関数を宣言
─MySQL コネクションを利用した SQL 実行を行う関数を宣言
 今後いろいろ利用する ミリ秒付きの日付文字列を取得する関数を宣言


■次にプログラムファイルの編集(Application.cpp)
tradeclient]# vi Application.cpp
ーー全文ーーーーーーーーーーーーーーーーーーーーーー
        #ifdef _MSC_VER
        #pragma warning( disable : 4503 4355 4786 )
        #else
        #include "config.h"
        #endif

        #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")));
          }

       if (FIX::MsgType_TestRequest == message.getHeader().getField(FIX::FIELD::MsgType))
            InsertTestRequest( message );

        }

        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
            {
              char action;
              std::cout << std::endl
                << "1) TestRequest Trade"  << std::endl
                << "2) TestRequest Ratefeed"  << std::endl
                << "q) Quit"  << std::endl
                << "Action: ";
              std::cin >> action;

              if      ( action == '1' ) TestRequest( SessionTypeTrade );
              else if ( action == '2' ) TestRequest( SessionTypeRatefeed );
              else if ( action == 'q' )
                break;
            }
            catch ( std::exception & e )
            {
              std::cout << "Message Not Sent: " << e.what();
            }
          }
        }

        void Application::SetMessageHeader( FIX::Message& message, const char* sessionType )
        {
          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)
            {
              message.getHeader().setField((FIX::SenderCompID)dic.getString("SenderCompID"));
              message.getHeader().setField((FIX::TargetCompID)dic.getString("TargetCompID"));
            }
          }
        }

     void Application::MySQLConnect()
        {
          std::string database = FIX::MySQLStoreFactory::DEFAULT_DATABASE;
          std::string password = FIX::MySQLStoreFactory::DEFAULT_PASSWORD;
          std::string user = FIX::MySQLStoreFactory::DEFAULT_USER;
          std::string host = FIX::MySQLStoreFactory::DEFAULT_HOST;
          short port = FIX::MySQLStoreFactory::DEFAULT_PORT;

          const FIX::Dictionary dic = m_settings.get();
          if (dic.has("MySQLStoreDatabase")) database = dic.getString("MySQLStoreDatabase");
          if (dic.has("MySQLStorePassword")) password = dic.getString("MySQLStorePassword");
          if (dic.has("MySQLStoreUser")) user = dic.getString("MySQLStoreUser");
          if (dic.has("MySQLStoreHost")) host = dic.getString("MySQLStoreHost");
          if (dic.has("MySQLStorePort")) port = dic.getInt("MySQLStorePort");

          m_sql = new  FIX::MySQLConnection( database, user, password, host, port );
        }


     FIX::MySQLQuery Application::MySQLExec( const std::string& q )
        {
          FIX::MySQLQuery query( q );
          if( !m_sql->execute(query))
          {
            syslog(LOG_ALERT, "SQL Error: %s", query.reason().c_str());
            syslog(LOG_ALERT, "SQL : %s", q.c_str());
          }
          return query;
        }


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

ーーーーーーーーーーーーーーーーーーーーーーーー
 TestRequest 送信時(toAdmin)にDB へ Insert する関数を呼び出す
◆MySQLへコネクションを張って m_sql に保存しとく
 SQL を実行する エラー時には syslog へ内容を吐き出す
ぁ.潺衂湛の日時を戻す YYYYmmdd-HHMMSS.sss 


■実験用のTestRequest プログラムの更新(TestRequest.cpp)
DBへのインサートや SELECT のサンプルを組み込んどきます。
tradeclient]# vi TestRequest.cpp
ーー全文ーーーーーーーーーーーーーーーーーーーーーー
        #ifdef _MSC_VER
        #pragma warning( disable : 4503 4355 4786 )
        #else
        #include "config.h"
        #endif

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

        /* < 1 > */
        void Application::TestRequest( const char* sessionType )
        {
          FIX44::TestRequest msg(
       /* 112  */ FIX::TestReqID( "TestReq_" + YmdHMSs() )
          );

          SetMessageHeader( msg, sessionType );
          FIX::Session::sendToTarget( msg );
        }

     void Application::InsertTestRequest( const FIX::Message& msg )
        {
       /* 112  */ FIX::FieldBase testReqID(FIX::FIELD::TestReqID, "0");
          /* 49   */ FIX::FieldBase sender(FIX::FIELD::SenderCompID, "0");
          /* 55   */ FIX::FieldBase symbol(FIX::FIELD::Symbol, "0");

       msg.getFieldIfSet(testReqID);
          msg.getHeader().getFieldIfSet(sender);
          msg.getFieldIfSet(symbol);


          /** insert **/
       std::ostringstream s;
          s <<  "INSERT INTO `test_request` " <<
            "( " <<
              " `TestReqID`"    <<
              ",`SenderCompID`" <<
            ") VALUES ("     <<
              " '" << testReqID << "'" <<
              ",'" << sender    << "'" <<
            ") ON DUPLICATE KEY UPDATE `TestReqID` = '" << testReqID << "'";

       MySQLExec( s.str() );


          /** get insert id  **/
       FIX::MySQLQuery q1 = MySQLExec("SELECT @@identity AS id");


          /** select insert column **/
       std::ostringstream s2;
          s2 << "SELECT `id`, `TestReqID`, `SenderCompID`, `Created_at` " <<
            "      FROM `test_request`" <<
            "     WHERE `id` = '" << q1.getValue(0,0) << "'";

       FIX::MySQLQuery q2 = MySQLExec( s2.str() );

          /** show insert column **/
       std::cout << "row - " << q2.rows() << std::endl;
          std::cout <<
            q2.getValue(0,0) << "       " <<
            q2.getValue(0,1) << "       " <<
            q2.getValue(0,2) << "       " <<
            q2.getValue(0,3) << std::endl;

        }

ーーーーーーーーーーーーーーーーーーーーーーーー
 TestRequestID に 文字列"TestReq_" と 追加した ミリ秒付き日時を指定
◆TestRequest送信時にメッセージ内容をDBにInsertする
 メッセージから情報を取得する変数を用意(メッセージ内になかった場合の初期値を指定)
  ※ メッセージ内に情報がなかった場合のサンプルとして Symbol を使ってみる
ぁ.瓮奪察璽犬ら欲しい情報だけを取得
  ※ メッセージ内に存在しない Symbol を取ろうとしてもエラーにならないことを確認
ァInsert文を組み立て
  ※ 万一 ID が被った場合は UPDATE になるように指定(MySQLのみの手法、Oracle はMarge?)
ΑInsert 実行
А…樵阿 Insert で自動付与された ID をSELECT

─ー動付与されたIDを使ってSELECT文を組み立て
 SELECT 実行
 SELECT の結果、取得したレコード数を確認
 SELECT の結果の1レコード目のみを取得、表示



■TestRequest用のDBテーブルを作成
以下でDBテーブルを作成。
作成後には定義を表示してみる
    tradeclient]# echo '
    DROP TABLE IF EXISTS test_request;
    CREATE TABLE test_request
    (
      `id`               INT UNSIGNED  NOT NULL  AUTO_INCREMENT,
      `TestReqID`        VARCHAR(64)   NOT NULL                  COMMENT "112",
      `SenderCompID`     VARCHAR(64)   NOT NULL                  COMMENT "49",
      `Created_at`       DATETIME      NOT NULL  DEFAULT CURRENT_TIMESTAMP,
      `Updated_at`       DATETIME      NOT NULL  DEFAULT CURRENT_TIMESTAMP  ON UPDATE CURRENT_TIMESTAMP,
      `Deleted_at`       DATETIME      NULL,
      PRIMARY KEY (`id`),
      UNIQUE `idxTestRequest_TestReqID` (`TestReqID`)
    ) ENGINE = InnoDB; 

    show tables; 
    desc test_request;
    ' | mysql -u DBuser -p quickfix
    Enter password:
    Tables_in_quickfix
    event_backup_log
    event_log
    messages_backup_log
    messages_log
    sessions
    test_request

    Field   Type    Null    Key     Default Extra
    id      int(10) unsigned        NO      PRI     NULL    auto_increment
    TestReqID       varchar(64)     NO      UNI     NULL
    SenderCompID    varchar(64)     NO              NULL
    Created_at      datetime        NO              CURRENT_TIMESTAMP
    Updated_at      datetime        NO              CURRENT_TIMESTAMP       on update CURRENT_TIMESTAMP
    Deleted_at      datetime        YES             NULL




■コンパイル(エラーもワーニングも出ないこと)
そして、コンパイル
tradeclient]# make clean
tradeclient]# make


■設定ファイルのデバッグフラグをコメントアウト
tradeclient]# cd ..
examples]# vi tradeclient.cfg
 −−−抜粋ーーーーーーーーーーーーーーーーーーーー
        [SESSION]
        BeginString=FIX.4.4
        SenderCompID=CAXDemo_Account_Trd
        TargetCompID=CNX
        SocketConnectHost=127.0.0.1
        SocketConnectPort=9999
        HeartBtInt=30
        Password=Pass1234
        SessionType=Trade
        # Debug_h_TradingSessionStatus=true

 ーーーーーーーーーーーーーーーーーーーーーーーーー


■動作確認
Stunnel が起動してなければ起動してから、クライアントを起動
# stunnel
examples]# ./tradeclient/tradeclient tradeclient.cfg
        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
        Action:
        Logon - FIX.4.4:CAXDemo_Account_Str->CNX

        IN: 8=FIX.4.49=8035=h34=249=CNX52=20160329-22:21:29.25056=CAXDemo_Account_Str336=0340=210=079

        Logon - FIX.4.4:CAXDemo_Account_Trd->CNX

        IN: 8=FIX.4.49=8035=h34=249=CNX52=20160329-22:21:29.25356=CAXDemo_Account_Trd336=0340=210=067
     1
     row - 1
        1       TestReq_20160329-222132.905     CAXDemo_Account_Trd  2016-03-30 07:21:32


        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
     Action: 2
     row - 1
        2       TestReq_20160329-222136.595     CAXDemo_Account_Str  2016-03-30 07:21:36


        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
     Action: 2
     row - 1
        3       TestReq_20160329-222139.055     CAXDemo_Account_Str  2016-03-30 07:21:39

 
        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
     Action: 2
     row - 1
        4       TestReq_20160329-222139.385     CAXDemo_Account_Str  2016-03-30 07:21:39


        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
     Action: 1
     row - 1
        5       TestReq_20160329-222142.785     CAXDemo_Account_Trd  2016-03-30 07:21:42


        1) TestRequest Trade
        2) TestRequest Ratefeed
        q) Quit
        Action: q

        Logout - FIX.4.4:CAXDemo_Account_Str->CNX

        Logout - FIX.4.4:CAXDemo_Account_Trd->CNX

ーーーーーーーーーーーーーーーーーーーーーーーーー
 TestRequest − Trade アカウント
◆Insert されて(ID 1)SELECT( TestReqID もちゃんと ミリ秒付き日時が設定されてる)

 TestRequest − Ratefeed(Str) アカウント 
ぁInsert されて(ID 2)SELECT
 TestRequest − Ratefeed(Str) アカウントを間髪入れずに連続実行
ΑInsert されて(ID 3、ID 4)SELECT
АTestRequest − Trade アカウント
─Insert されて(ID 5)SELECT




一応DBも見てみる
    examples]# echo 'SELECT *  FROM test_request' | mysql -uDBuser -pDBpass quickfix
    mysql: [Warning] Using a password on the command line interface can be insecure.
    id      TestReqID       SenderCompID    Created_at      Updated_at      Deleted_at
    1       TestReq_20160329-222132.905     CAXDemo_Account_Trd  2016-03-30 07:21:32     2016-03-30 07:21:32     NULL
    2       TestReq_20160329-222136.595     CAXDemo_Account_Str  2016-03-30 07:21:36     2016-03-30 07:21:36     NULL
    3       TestReq_20160329-222139.055     CAXDemo_Account_Str  2016-03-30 07:21:39     2016-03-30 07:21:39     NULL
    4       TestReq_20160329-222139.385     CAXDemo_Account_Str  2016-03-30 07:21:39     2016-03-30 07:21:39     NULL
    5       TestReq_20160329-222142.785     CAXDemo_Account_Trd  2016-03-30 07:21:42     2016-03-30 07:21:42     NULL





ちゃーーんとDBへのInsert と Selectができている模様!!
独自テーブルへのINSET & SELECT は成功です






 
まこ | FIX | 01:07 | comments(0) | trackbacks(0) |
スポンサーサイト
スポンサードリンク | - | 01:07 | - | - |
Comment









Trackback
URL: