├── .gitignore ├── README.md ├── bid_ask_schematic.txt ├── ordermatch ├── Application.cpp ├── Application.h ├── IDGenerator.h ├── Makefile ├── Market.cpp ├── Market.h ├── Order.h ├── OrderMatcher.h ├── ordermatch.cfg └── ordermatch.cpp ├── spec ├── FIX50SP2.xml └── FIXT11.xml └── tradeclient ├── Application.cpp ├── Application.h ├── Makefile ├── tradeclient.cfg └── tradeclient.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | *.o 3 | ordermatch/prog 4 | tradeclient/prog 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuickFIX Trading Platform 2 | Basic C++ FIX trading platform using the QuickFIX Engine. 3 | 4 | ### Motivation 5 | I was recently involved in implementing a [FIX](http://www.fixprotocol.org/) message client. 6 | We are using our own proprietary FIX engine to implement it, but I was urged to have a look 7 | at the QuickFIX Engine. This project is based massively on the example code that comes with 8 | the engine. I just removed support for the various FIX protocol versions and kept only 9 | FIX 5.0 SP2. Also made a few changes/additions to the matching engine to return 10 | a FIX 5.0 SP2 `FIX::ExecutionReport` message with all the required fields. 11 | 12 | ### Description 13 | The project contains two tasks, *tradeclient* and *ordermatch*. They are both console 14 | based. The first sends orders and the latter stores them and tries to make a match. 15 | On success it sends `FIX::ExecutionReport` messages with the matched trade details. 16 | 17 | ### Implementation Details 18 | A few implementation details: 19 | 20 | * The *ordermatch* task stores the orders in `Order` instances. The `Order` class holds 21 | two `std::multimap` containers, one for *Buy* and one for *Sell* orders. 22 | * For each financial instrument we have a `Market`. The `Market`'s name is based on 23 | the instrument's `FIX::Symbol` tag value. 24 | * Both tasks store their incoming/outgoing FIX messages in plain text files in a 25 | folder named `./store/`. 26 | 27 | ### Task *tradeclient* 28 | The task displays a command line menu where you can send messages to *ordermatch*. 29 | It also prints out all incoming and outgoing FIX protocol messages. 30 | 31 | ### Task *ordermatch* 32 | The task is not displaying a command line menu but it supports a few commands. 33 | 34 | * `#symbols` - Display all the active `Market` instances of the `OrderMatcher`. 35 | * `#quit` - Disconnect any active connections and shutdown. 36 | * `` - Display all *Bid* and *Ask* orders for the `Market` matching the string. 37 | A `Market`'s name is based on the financial instrument's `FIX::Symbol` tag value. 38 | 39 | ### Library Requirements 40 | One third party library needed: 41 | 42 | * [quickfix](http://www.quickfixengine.org/) - The QuickFIX Engine. 43 | 44 | ***NOTE***: I downloaded the sources and build my own QuickFIX Engine library. 45 | During the `configure` step the file `config.h` is generated. This file is 46 | included into the example code that comes with the package. It contains `define` 47 | statements for the various tools the library was built to have support for. For 48 | example support to store the FIX messages in a database (mySQL, PostgreSQL etc). 49 | I copied this header file by hand in my `include` directory. You can either do the 50 | same or just remove the `#include` line. Not sure if it's needed anyway. I just 51 | kept it to be on the safe side. 52 | 53 | -------------------------------------------------------------------------------- /bid_ask_schematic.txt: -------------------------------------------------------------------------------- 1 | 80 2 | 81 3 | 82 /\ 4 | 83 | 5 | 84 | BID 6 | 85 | 7 | 86 8 | 87 begin() 9 | 10 | 11 | 90 begin() 12 | 91 13 | 92 | 14 | 93 | ASK 15 | 94 | 16 | 95 \/ 17 | 96 18 | 97 19 | -------------------------------------------------------------------------------- /ordermatch/Application.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) quickfixengine.org All rights reserved. 3 | ** 4 | ** This file is part of the QuickFIX FIX Engine 5 | ** 6 | ** This file may be distributed under the terms of the quickfixengine.org 7 | ** license as defined by quickfixengine.org and appearing in the file 8 | ** LICENSE included in the packaging of this file. 9 | ** 10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12 | ** 13 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 14 | ** 15 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 16 | ** not clear to you. 17 | ** 18 | ****************************************************************************/ 19 | 20 | #include "Application.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | void Application::onLogon(const FIX::SessionID& sessionID) 27 | { } 28 | 29 | void Application::onLogout(const FIX::SessionID& sessionID) 30 | { } 31 | 32 | void Application::fromApp(const FIX::Message& message, 33 | const FIX::SessionID& sessionID) 34 | throw(FIX::FieldNotFound, 35 | FIX::IncorrectDataFormat, 36 | FIX::IncorrectTagValue, 37 | FIX::UnsupportedMessageType) 38 | { 39 | crack(message, sessionID); 40 | } 41 | 42 | void Application::onMessage(const FIX50::NewOrderSingle& message, 43 | const FIX::SessionID&) 44 | { 45 | FIX::SenderCompID senderCompID; 46 | FIX::TargetCompID targetCompID; 47 | FIX::ClOrdID clOrdID; 48 | FIX::Symbol symbol; 49 | FIX::Side side; 50 | FIX::OrdType ordType; 51 | FIX::Price price; 52 | FIX::OrderQty orderQty; 53 | FIX::TimeInForce timeInForce(FIX::TimeInForce_DAY); 54 | 55 | message.getHeader().getField(senderCompID); 56 | message.getHeader().getField(targetCompID); 57 | message.get(clOrdID); 58 | message.get(symbol); 59 | message.get(side); 60 | message.get(ordType); 61 | if (ordType == FIX::OrdType_LIMIT) { 62 | message.get(price); 63 | } 64 | message.get(orderQty); 65 | if (message.isSetField(timeInForce)) { 66 | message.get( timeInForce ); 67 | } 68 | 69 | try { 70 | if (timeInForce != FIX::TimeInForce_DAY) { 71 | throw std::logic_error("Unsupported TIF, use Day"); 72 | } 73 | 74 | Order order(clOrdID, symbol, senderCompID, targetCompID, 75 | convert(side), convert(ordType), 76 | price, (long)orderQty); 77 | 78 | processOrder(order); 79 | } 80 | catch(std::exception & e) { 81 | rejectOrder(senderCompID, targetCompID, clOrdID, symbol, side, e.what()); 82 | } 83 | } 84 | 85 | void Application::onMessage(const FIX50::OrderCancelRequest& message, 86 | const FIX::SessionID&) 87 | { 88 | FIX::OrigClOrdID origClOrdID; 89 | FIX::Symbol symbol; 90 | FIX::Side side; 91 | 92 | message.get(origClOrdID); 93 | message.get(symbol); 94 | message.get(side); 95 | 96 | try { 97 | processCancel(origClOrdID, symbol, convert(side)); 98 | } 99 | catch(std::exception&) { 100 | } 101 | } 102 | 103 | void Application::onMessage(const FIX50::MarketDataRequest& message, 104 | const FIX::SessionID&) 105 | { 106 | FIX::MDReqID mdReqID; 107 | FIX::SubscriptionRequestType subscriptionRequestType; 108 | FIX::MarketDepth marketDepth; 109 | FIX::NoRelatedSym noRelatedSym; 110 | FIX50::MarketDataRequest::NoRelatedSym noRelatedSymGroup; 111 | 112 | message.get(mdReqID); 113 | message.get(subscriptionRequestType); 114 | if (subscriptionRequestType != FIX::SubscriptionRequestType_SNAPSHOT) { 115 | throw(FIX::IncorrectTagValue(subscriptionRequestType.getField())); 116 | } 117 | message.get(marketDepth); 118 | message.get(noRelatedSym); 119 | 120 | for (int i = 1; i <= noRelatedSym; ++i) { 121 | FIX::Symbol symbol; 122 | message.getGroup(i, noRelatedSymGroup); 123 | noRelatedSymGroup.get(symbol); 124 | } 125 | } 126 | 127 | void Application::updateOrder(const Order& order, 128 | char status) 129 | { 130 | FIX::TargetCompID targetCompID(order.getOwner()); 131 | FIX::SenderCompID senderCompID(order.getTarget()); 132 | 133 | FIX50::ExecutionReport fixOrder (FIX::OrderID(order.getClientID()), 134 | FIX::ExecID(m_generator.genExecutionID()), 135 | FIX::ExecType(status), 136 | FIX::OrdStatus(status), 137 | FIX::Side(convert(order.getSide())), 138 | FIX::LeavesQty(order.getOpenQuantity()), 139 | FIX::CumQty(order.getExecutedQuantity())); 140 | 141 | fixOrder.setField(FIX::ClOrdID(order.getClientID())); 142 | fixOrder.setField(FIX::OrderQty(order.getQuantity())); 143 | 144 | if (status == FIX::OrdStatus_FILLED || 145 | status == FIX::OrdStatus_PARTIALLY_FILLED) 146 | { 147 | fixOrder.setField(FIX::LastShares(order.getLastExecutedQuantity())); 148 | fixOrder.setField(FIX::LastPx(order.getLastExecutedPrice())); 149 | fixOrder.setField(FIX::ExecType(FIX::ExecType_TRADE)); 150 | } 151 | 152 | try { 153 | FIX::Session::sendToTarget(fixOrder, senderCompID, targetCompID); 154 | } 155 | catch(FIX::SessionNotFound&) { 156 | } 157 | } 158 | 159 | void Application::rejectOrder(const FIX::SenderCompID& sender, 160 | const FIX::TargetCompID& target, 161 | const FIX::ClOrdID& clOrdID, 162 | const FIX::Symbol& symbol, 163 | const FIX::Side& side, 164 | const std::string& message) 165 | { 166 | FIX::TargetCompID targetCompID(sender.getValue()); 167 | FIX::SenderCompID senderCompID(target.getValue()); 168 | 169 | FIX50::ExecutionReport fixOrder(FIX::OrderID(clOrdID.getValue()), 170 | FIX::ExecID(m_generator.genExecutionID()), 171 | FIX::ExecType(FIX::ExecType_REJECTED), 172 | FIX::OrdStatus(FIX::ExecType_REJECTED), 173 | side, 174 | FIX::LeavesQty(0), 175 | FIX::CumQty(0)); 176 | 177 | fixOrder.setField(clOrdID); 178 | fixOrder.setField(FIX::Text(message)); 179 | 180 | try { 181 | FIX::Session::sendToTarget( fixOrder, senderCompID, targetCompID ); 182 | } 183 | catch(FIX::SessionNotFound&) { 184 | } 185 | } 186 | 187 | void Application::processOrder( const Order& order ) 188 | { 189 | if (m_orderMatcher.insert(order)) 190 | { 191 | acceptOrder(order); 192 | 193 | std::queue orders; 194 | m_orderMatcher.match(order.getSymbol(), 195 | orders); 196 | 197 | while (orders.size()) { 198 | fillOrder(orders.front()); 199 | orders.pop(); 200 | } 201 | } 202 | else { 203 | rejectOrder(order); 204 | } 205 | } 206 | 207 | void Application::processCancel(const std::string& id, 208 | const std::string& symbol, 209 | Order::Side side ) 210 | { 211 | Order & order = m_orderMatcher.find(symbol, side, id); 212 | order.cancel(); 213 | cancelOrder(order); 214 | m_orderMatcher.erase(order); 215 | } 216 | 217 | Order::Side Application::convert(const FIX::Side& side) const 218 | { 219 | switch (side) { 220 | case FIX::Side_BUY: { 221 | return Order::buy; 222 | } 223 | break; 224 | case FIX::Side_SELL: { 225 | return Order::sell; 226 | } 227 | break; 228 | default: { 229 | throw std::logic_error("Unsupported Side, use buy or sell"); 230 | } 231 | break; 232 | } 233 | } 234 | 235 | Order::Type Application::convert(const FIX::OrdType& ordType) const 236 | { 237 | switch (ordType) { 238 | case FIX::OrdType_LIMIT: { 239 | return Order::limit; 240 | } 241 | break; 242 | default: { 243 | throw std::logic_error("Unsupported Order Type, use limit"); 244 | } 245 | break; 246 | } 247 | } 248 | 249 | FIX::Side Application::convert(Order::Side side) const 250 | { 251 | switch (side) { 252 | case Order::buy: { 253 | return FIX::Side(FIX::Side_BUY); 254 | } 255 | break; 256 | case Order::sell: { 257 | return FIX::Side(FIX::Side_SELL); 258 | } 259 | break; 260 | default: { 261 | throw std::logic_error("Unsupported Side, use buy or sell"); 262 | } 263 | break; 264 | } 265 | } 266 | 267 | FIX::OrdType Application::convert(Order::Type type) const 268 | { 269 | switch (type) { 270 | case Order::limit: { 271 | return FIX::OrdType(FIX::OrdType_LIMIT); 272 | } 273 | break; 274 | default: { 275 | throw std::logic_error("Unsupported Order Type, use limit"); 276 | } 277 | break; 278 | } 279 | } 280 | 281 | -------------------------------------------------------------------------------- /ordermatch/Application.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef ORDERMATCH_APPLICATION_H 23 | #define ORDERMATCH_APPLICATION_H 24 | 25 | #include "IDGenerator.h" 26 | #include "OrderMatcher.h" 27 | #include "Order.h" 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | class Application : public FIX::Application, 42 | public FIX::MessageCracker 43 | { 44 | /*! 45 | * Overload for class 'FIX::Application'. 46 | */ 47 | 48 | /*! 49 | * @brief Callback for Session create. 50 | * @details Callback function when the FIX Session gets 51 | * created. 52 | * @param param1 The FIX Session ID. 53 | */ 54 | void onCreate(const FIX::SessionID&) 55 | { } 56 | 57 | /*! 58 | * @brief Callback for Logon. 59 | * @details Callback function when the FIX Session receives 60 | * a FIX Logon message. 61 | * @param param1 The FIX Session ID. 62 | */ 63 | void onLogon(const FIX::SessionID& sessionID); 64 | 65 | /*! 66 | * @brief Callback for Logout. 67 | * @details Callback function when the FIX Session receives 68 | * a FIX Logout message. 69 | * @param param1 The FIX Session ID. 70 | */ 71 | void onLogout(const FIX::SessionID& sessionID); 72 | 73 | /*! 74 | * @brief 75 | * @details 76 | * @param 77 | */ 78 | void toAdmin(FIX::Message&, 79 | const FIX::SessionID&) 80 | { } 81 | 82 | /*! 83 | * @brief 84 | * @details 85 | * @param 86 | */ 87 | void toApp(FIX::Message&, 88 | const FIX::SessionID&) 89 | throw(FIX::DoNotSend) 90 | { } 91 | 92 | /*! 93 | * @brief 94 | * @details 95 | * @param 96 | */ 97 | void fromAdmin(const FIX::Message&, 98 | const FIX::SessionID&) 99 | throw(FIX::FieldNotFound, 100 | FIX::IncorrectDataFormat, 101 | FIX::IncorrectTagValue, 102 | FIX::RejectLogon) 103 | { } 104 | 105 | /*! 106 | * @brief 107 | * @details 108 | * @param 109 | */ 110 | void fromApp(const FIX::Message& message, 111 | const FIX::SessionID& sessionID) 112 | throw(FIX::FieldNotFound, 113 | FIX::IncorrectDataFormat, 114 | FIX::IncorrectTagValue, 115 | FIX::UnsupportedMessageType); 116 | 117 | /*! 118 | * Overload for class 'FIX::MessageCracker'. 119 | */ 120 | 121 | /*! 122 | * @brief Callback for NewOrderSingle. 123 | * @details Callback function when a NewOrderSingle message is 124 | * received. It extracts all the necessary fields from 125 | * the incoming message in order to fully initialize an 126 | * 'Order' object and then it call a function to 127 | * process it. 128 | * @param param1 The incoming NewOrderSingle object. 129 | * @param param2 The FIX Session ID. 130 | */ 131 | void onMessage(const FIX50::NewOrderSingle&, 132 | const FIX::SessionID&); 133 | 134 | /*! 135 | * @brief 136 | * @details 137 | * @param 138 | */ 139 | void onMessage(const FIX50::OrderCancelRequest&, 140 | const FIX::SessionID&); 141 | 142 | /*! 143 | * @brief 144 | * @details 145 | * @param 146 | */ 147 | void onMessage(const FIX50::MarketDataRequest&, 148 | const FIX::SessionID&); 149 | 150 | // Order functionality 151 | 152 | /*! 153 | * @brief 154 | * @details 155 | * @param 156 | */ 157 | void processOrder(const Order&); 158 | 159 | /*! 160 | * @brief 161 | * @details 162 | * @param 163 | */ 164 | void processCancel(const std::string& id, 165 | const std::string& symbol, 166 | Order::Side); 167 | 168 | /*! 169 | * @brief 170 | * @details 171 | * @param 172 | */ 173 | void updateOrder(const Order&, char status); 174 | 175 | /*! 176 | * @brief 177 | * @details 178 | * @param 179 | */ 180 | void rejectOrder(const Order& order) 181 | { 182 | updateOrder(order, 183 | FIX::OrdStatus_REJECTED); 184 | } 185 | 186 | /*! 187 | * @brief 188 | * @details 189 | * @param 190 | */ 191 | void acceptOrder(const Order& order) 192 | { 193 | updateOrder(order, 194 | FIX::OrdStatus_NEW); 195 | } 196 | 197 | /*! 198 | * @brief 199 | * @details 200 | * @param 201 | */ 202 | void fillOrder(const Order& order) 203 | { 204 | updateOrder(order, 205 | order.isFilled() ? FIX::OrdStatus_FILLED 206 | : FIX::OrdStatus_PARTIALLY_FILLED); 207 | } 208 | 209 | /*! 210 | * @brief 211 | * @details 212 | * @param 213 | */ 214 | void cancelOrder(const Order& order) 215 | { 216 | updateOrder(order, 217 | FIX::OrdStatus_CANCELED); 218 | } 219 | 220 | /*! 221 | * @brief 222 | * @details 223 | * @param 224 | */ 225 | void rejectOrder(const FIX::SenderCompID&, 226 | const FIX::TargetCompID&, 227 | const FIX::ClOrdID& clOrdID, 228 | const FIX::Symbol& symbol, 229 | const FIX::Side& side, 230 | const std::string& message); 231 | 232 | // Type conversions 233 | 234 | /*! 235 | * @brief Convert FIX::Side enumeration. 236 | * @details Convert FIX::Side enumeration to the internal 237 | * Order::Side equivalent. 238 | * @param param1 The FIX::Side to convert. 239 | * @return The Order::Side enumeration. 240 | */ 241 | Order::Side convert(const FIX::Side&) const; 242 | 243 | /*! 244 | * @brief Convert FIX::OrdType enumeration. 245 | * @details Convert FIX::OrdType enumeration to the internal 246 | * Order::Type equivalent. 247 | * @param param1 The FIX::OrdType to convert. 248 | * @return The Order::Type enumeration. 249 | */ 250 | Order::Type convert(const FIX::OrdType&) const; 251 | 252 | /*! 253 | * @brief Convert Order::Side enumeration. 254 | * @details Convert Order::Side enumeration to the FIX 255 | * FIX::Type equivalent. 256 | * @param param1 The Order::Side to convert. 257 | * @return The FIX::Side enumeration. 258 | */ 259 | FIX::Side convert(Order::Side) const; 260 | 261 | /*! 262 | * @brief Convert Order::Type enumeration. 263 | * @details Convert Order::Type enumeration to the FIX 264 | * FIX::OrdType equivalent. 265 | * @param param1 The Order::Type to convert. 266 | * @return The FIX::OrdType enumeration. 267 | */ 268 | FIX::OrdType convert(Order::Type) const; 269 | 270 | OrderMatcher m_orderMatcher; 271 | IDGenerator m_generator; 272 | 273 | public: 274 | 275 | /*! 276 | * @brief 277 | * @details 278 | * @param 279 | */ 280 | const OrderMatcher& orderMatcher() const 281 | { 282 | return m_orderMatcher; 283 | } 284 | }; 285 | 286 | #endif 287 | -------------------------------------------------------------------------------- /ordermatch/IDGenerator.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef ORDERMATCH_IDGENERATOR_H 23 | #define ORDERMATCH_IDGENERATOR_H 24 | 25 | #include 26 | #include 27 | 28 | class IDGenerator 29 | { 30 | public: 31 | IDGenerator() : m_orderID( 0 ), m_executionID( 0 ) {} 32 | 33 | std::string genOrderID() 34 | { 35 | std::stringstream stream; 36 | stream << ++m_orderID; 37 | return stream.str(); 38 | } 39 | 40 | std::string genExecutionID() 41 | { 42 | std::stringstream stream; 43 | stream << ++m_executionID; 44 | return stream.str(); 45 | } 46 | 47 | private: 48 | long m_orderID; 49 | long m_executionID; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /ordermatch/Makefile: -------------------------------------------------------------------------------- 1 | 2 | MF= Makefile 3 | 4 | CC= g++ 5 | 6 | CFLAGS=-I$(HOME)/local_software/include 7 | LFLAGS=-L$(HOME)/local_software/lib -lquickfix 8 | PREPROC= 9 | 10 | EXE= prog 11 | SRC= Application.cpp \ 12 | Market.cpp \ 13 | ordermatch.cpp 14 | 15 | OBJ= $(SRC:.cpp=.o) 16 | 17 | INC= IDGenerator.h \ 18 | Order.h \ 19 | OrderMatcher.h \ 20 | 21 | 22 | .SUFFIXES: 23 | .SUFFIXES: .cpp .o 24 | 25 | all: $(EXE) 26 | 27 | .cpp.o: 28 | $(CC) $(CFLAGS) $(PREPROC) -c $< 29 | 30 | $(EXE): $(OBJ) 31 | $(CC) $(CFLAGS) -o $@ $(OBJ) $(LFLAGS) 32 | 33 | $(OBJ): $(SRC) $(INC) $(MF) 34 | 35 | clean: 36 | rm -f *.o $(EXE) core 37 | 38 | relink: 39 | rm -f $(EXE) 40 | $(MAKE) 41 | 42 | run: 43 | ./prog 44 | 45 | -------------------------------------------------------------------------------- /ordermatch/Market.cpp: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifdef _MSC_VER 23 | #pragma warning( disable : 4786 ) 24 | #endif 25 | 26 | #include "Market.h" 27 | #include 28 | 29 | bool Market::insert( const Order& order ) 30 | { 31 | if ( order.getSide() == Order::buy ) 32 | m_bidOrders.insert( BidOrders::value_type( order.getPrice(), order ) ); 33 | else 34 | m_askOrders.insert( AskOrders::value_type( order.getPrice(), order ) ); 35 | return true; 36 | } 37 | 38 | void Market::erase( const Order& order ) 39 | { 40 | std::string id = order.getClientID(); 41 | if ( order.getSide() == Order::buy ) 42 | { 43 | BidOrders::iterator i; 44 | for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i ) 45 | if ( i->second.getClientID() == id ) 46 | { 47 | m_bidOrders.erase( i ); 48 | return ; 49 | } 50 | } 51 | else if ( order.getSide() == Order::sell ) 52 | { 53 | AskOrders::iterator i; 54 | for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i ) 55 | if ( i->second.getClientID() == id ) 56 | { 57 | m_askOrders.erase( i ); 58 | return ; 59 | } 60 | } 61 | } 62 | 63 | bool Market::match( std::queue < Order > & orders ) 64 | { 65 | while ( true ) 66 | { 67 | if ( !m_bidOrders.size() || !m_askOrders.size() ) 68 | return orders.size() != 0; 69 | 70 | BidOrders::iterator iBid = m_bidOrders.begin(); 71 | AskOrders::iterator iAsk = m_askOrders.begin(); 72 | 73 | if ( iBid->second.getPrice() >= iAsk->second.getPrice() ) 74 | { 75 | Order & bid = iBid->second; 76 | Order& ask = iAsk->second; 77 | 78 | match( bid, ask ); 79 | orders.push( bid ); 80 | orders.push( ask ); 81 | 82 | if ( bid.isClosed() ) m_bidOrders.erase( iBid ); 83 | if ( ask.isClosed() ) m_askOrders.erase( iAsk ); 84 | } 85 | else 86 | return orders.size() != 0; 87 | } 88 | } 89 | 90 | Order& Market::find( Order::Side side, std::string id ) 91 | { 92 | if ( side == Order::buy ) 93 | { 94 | BidOrders::iterator i; 95 | for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i ) 96 | if ( i->second.getClientID() == id ) return i->second; 97 | } 98 | else if ( side == Order::sell ) 99 | { 100 | AskOrders::iterator i; 101 | for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i ) 102 | if ( i->second.getClientID() == id ) return i->second; 103 | } 104 | throw std::exception(); 105 | } 106 | 107 | void Market::match( Order& bid, Order& ask ) 108 | { 109 | double price = ask.getPrice(); 110 | int quantity = 0; 111 | 112 | if ( bid.getOpenQuantity() > ask.getOpenQuantity() ) 113 | quantity = ask.getOpenQuantity(); 114 | else 115 | quantity = bid.getOpenQuantity(); 116 | 117 | bid.execute( price, quantity ); 118 | ask.execute( price, quantity ); 119 | } 120 | 121 | void Market::display() const 122 | { 123 | BidOrders::const_iterator iBid; 124 | AskOrders::const_iterator iAsk; 125 | 126 | std::cout << "BIDS:" << std::endl; 127 | std::cout << "-----" << std::endl << std::endl; 128 | for ( iBid = m_bidOrders.begin(); iBid != m_bidOrders.end(); ++iBid ) 129 | std::cout << iBid->second << std::endl; 130 | 131 | std::cout << std::endl << std::endl; 132 | 133 | std::cout << "ASKS:" << std::endl; 134 | std::cout << "-----" << std::endl << std::endl; 135 | for ( iAsk = m_askOrders.begin(); iAsk != m_askOrders.end(); ++iAsk ) 136 | std::cout << iAsk->second << std::endl; 137 | } 138 | -------------------------------------------------------------------------------- /ordermatch/Market.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef ORDERMATCH_MARKET_H 23 | #define ORDERMATCH_MARKET_H 24 | 25 | #include "Order.h" 26 | #include 27 | #include 28 | #include 29 | 30 | class Market 31 | { 32 | public: 33 | bool insert( const Order& order ); 34 | void erase( const Order& order ); 35 | Order& find( Order::Side side, std::string id ); 36 | bool match( std::queue < Order > & ); 37 | void display() const; 38 | 39 | private: 40 | typedef std::multimap < double, Order, std::greater < double > > BidOrders; 41 | typedef std::multimap < double, Order, std::less < double > > AskOrders; 42 | 43 | void match( Order& bid, Order& ask ); 44 | 45 | std::queue < Order > m_orderUpdates; 46 | BidOrders m_bidOrders; 47 | AskOrders m_askOrders; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /ordermatch/Order.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef ORDERMATCH_ORDER_H 23 | #define ORDERMATCH_ORDER_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | class Order 30 | { 31 | friend std::ostream& operator<<( std::ostream&, const Order& ); 32 | 33 | public: 34 | enum Side { buy, sell }; 35 | enum Type { market, limit }; 36 | 37 | Order( const std::string& clientId, const std::string& symbol, 38 | const std::string& owner, const std::string& target, 39 | Side side, Type type, double price, long quantity ) 40 | : m_clientId( clientId ), m_symbol( symbol ), m_owner( owner ), 41 | m_target( target ), m_side( side ), m_type( type ), m_price( price ), 42 | m_quantity( quantity ) 43 | { 44 | m_openQuantity = m_quantity; 45 | m_executedQuantity = 0; 46 | m_avgExecutedPrice = 0; 47 | m_lastExecutedPrice = 0; 48 | m_lastExecutedQuantity = 0; 49 | } 50 | 51 | const std::string& getClientID() const { return m_clientId; } 52 | const std::string& getSymbol() const { return m_symbol; } 53 | const std::string& getOwner() const { return m_owner; } 54 | const std::string& getTarget() const { return m_target; } 55 | Side getSide() const { return m_side; } 56 | Type getType() const { return m_type; } 57 | double getPrice() const { return m_price; } 58 | long getQuantity() const { return m_quantity; } 59 | 60 | long getOpenQuantity() const { return m_openQuantity; } 61 | long getExecutedQuantity() const { return m_executedQuantity; } 62 | double getAvgExecutedPrice() const { return m_avgExecutedPrice; } 63 | double getLastExecutedPrice() const { return m_lastExecutedPrice; } 64 | long getLastExecutedQuantity() const { return m_lastExecutedQuantity; } 65 | 66 | bool isFilled() const { return m_quantity == m_executedQuantity; } 67 | bool isClosed() const { return m_openQuantity == 0; } 68 | 69 | void execute( double price, long quantity ) 70 | { 71 | m_avgExecutedPrice = 72 | ( ( quantity * price ) + ( m_avgExecutedPrice * m_executedQuantity ) ) 73 | / ( quantity + m_executedQuantity ); 74 | 75 | m_openQuantity -= quantity; 76 | m_executedQuantity += quantity; 77 | m_lastExecutedPrice = price; 78 | m_lastExecutedQuantity = quantity; 79 | } 80 | void cancel() 81 | { 82 | m_openQuantity = 0; 83 | } 84 | 85 | private: 86 | std::string m_clientId; 87 | std::string m_symbol; 88 | std::string m_owner; 89 | std::string m_target; 90 | Side m_side; 91 | Type m_type; 92 | double m_price; 93 | long m_quantity; 94 | 95 | long m_openQuantity; 96 | long m_executedQuantity; 97 | double m_avgExecutedPrice; 98 | double m_lastExecutedPrice; 99 | long m_lastExecutedQuantity; 100 | }; 101 | 102 | inline std::ostream& operator<<( std::ostream& ostream, const Order& order ) 103 | { 104 | return ostream 105 | << "ID: " << std::setw( 10 ) << "," << order.getClientID() 106 | << " OWNER: " << std::setw( 10 ) << "," << order.getOwner() 107 | << " PRICE: " << std::setw( 10 ) << "," << order.getPrice() 108 | << " QUANTITY: " << std::setw( 10 ) << "," << order.getQuantity(); 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /ordermatch/OrderMatcher.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef ORDERMATCH_ORDERMATCHER_H 23 | #define ORDERMATCH_ORDERMATCHER_H 24 | 25 | #include "Market.h" 26 | #include 27 | #include 28 | 29 | class OrderMatcher 30 | { 31 | typedef std::map < std::string, Market > Markets; 32 | public: 33 | bool insert( const Order& order ) 34 | { 35 | Markets::iterator i = m_markets.find( order.getSymbol() ); 36 | if ( i == m_markets.end() ) 37 | i = m_markets.insert( std::make_pair( order.getSymbol(), Market() ) ).first; 38 | return i->second.insert( order ); 39 | } 40 | 41 | void erase( const Order& order ) 42 | { 43 | Markets::iterator i = m_markets.find( order.getSymbol() ); 44 | if ( i == m_markets.end() ) return ; 45 | i->second.erase( order ); 46 | } 47 | 48 | Order& find( std::string symbol, Order::Side side, std::string id ) 49 | { 50 | Markets::iterator i = m_markets.find( symbol ); 51 | if ( i == m_markets.end() ) throw std::exception(); 52 | return i->second.find( side, id ); 53 | } 54 | 55 | bool match( std::string symbol, std::queue < Order > & orders ) 56 | { 57 | Markets::iterator i = m_markets.find( symbol ); 58 | if ( i == m_markets.end() ) return false; 59 | return i->second.match( orders ); 60 | } 61 | 62 | bool match( std::queue < Order > & orders ) 63 | { 64 | Markets::iterator i; 65 | for ( i = m_markets.begin(); i != m_markets.end(); ++i ) 66 | i->second.match( orders ); 67 | return orders.size() != 0; 68 | } 69 | 70 | void display( std::string symbol ) const 71 | { 72 | Markets::const_iterator i = m_markets.find( symbol ); 73 | if ( i == m_markets.end() ) return ; 74 | i->second.display(); 75 | } 76 | 77 | void display() const 78 | { 79 | std::cout << "SYMBOLS:" << std::endl; 80 | std::cout << "--------" << std::endl; 81 | 82 | Markets::const_iterator i; 83 | for ( i = m_markets.begin(); i != m_markets.end(); ++i ) 84 | std::cout << i->first << std::endl; 85 | } 86 | 87 | private: 88 | Markets m_markets; 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /ordermatch/ordermatch.cfg: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | ConnectionType=acceptor 3 | SocketAcceptPort=5002 4 | SocketReuseAddress=Y 5 | FileStorePath=store 6 | StartTime=00:00:00 7 | EndTime=00:00:00 8 | DataDictionary=../spec/FIX50SP2.xml 9 | 10 | [SESSION] 11 | BeginString=FIXT.1.1 12 | DefaultApplVerID=FIX.5.0 13 | SenderCompID=ORDERMATCH 14 | TargetCompID=CLIENT1 15 | FileStorePath=store 16 | TransportDataDictionary=../spec/FIXT11.xml 17 | AppDataDictionary=../spec/FIX50SP2.xml 18 | 19 | -------------------------------------------------------------------------------- /ordermatch/ordermatch.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) quickfixengine.org All rights reserved. 3 | ** 4 | ** This file is part of the QuickFIX FIX Engine 5 | ** 6 | ** This file may be distributed under the terms of the quickfixengine.org 7 | ** license as defined by quickfixengine.org and appearing in the file 8 | ** LICENSE included in the packaging of this file. 9 | ** 10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12 | ** 13 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 14 | ** 15 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 16 | ** not clear to you. 17 | ** 18 | ****************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "Application.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | int main( int argc, char** argv ) 32 | { 33 | if ( argc != 2 ) 34 | { 35 | std::cout << "usage: " << argv[ 0 ] 36 | << " FILE." << std::endl; 37 | return 0; 38 | } 39 | std::string file = argv[ 1 ]; 40 | 41 | try 42 | { 43 | FIX::SessionSettings settings( file ); 44 | 45 | Application application; 46 | FIX::FileStoreFactory storeFactory( settings ); 47 | FIX::ScreenLogFactory logFactory( settings ); 48 | FIX::SocketAcceptor acceptor( application, storeFactory, settings, logFactory ); 49 | 50 | acceptor.start(); 51 | while ( true ) 52 | { 53 | std::string value; 54 | std::cin >> value; 55 | 56 | if ( value == "#symbols" ) 57 | application.orderMatcher().display(); 58 | else if( value == "#quit" ) 59 | break; 60 | else 61 | application.orderMatcher().display( value ); 62 | 63 | std::cout << std::endl; 64 | } 65 | acceptor.stop(); 66 | return 0; 67 | } 68 | catch ( std::exception & e ) 69 | { 70 | std::cout << e.what() << std::endl; 71 | return 1; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /spec/FIXT11.xml: -------------------------------------------------------------------------------- 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 | 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 |
314 | -------------------------------------------------------------------------------- /tradeclient/Application.cpp: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #include "Application.h" 23 | #include 24 | #include 25 | 26 | void Application::onLogon( const FIX::SessionID& sessionID ) 27 | { 28 | std::cout << std::endl << "Logon - " << sessionID << std::endl; 29 | } 30 | 31 | void Application::onLogout( const FIX::SessionID& sessionID ) 32 | { 33 | std::cout << std::endl << "Logout - " << sessionID << std::endl; 34 | } 35 | 36 | void Application::fromApp(const FIX::Message& message, 37 | const FIX::SessionID& sessionID ) 38 | throw(FIX::FieldNotFound, 39 | FIX::IncorrectDataFormat, 40 | FIX::IncorrectTagValue, 41 | FIX::UnsupportedMessageType) 42 | { 43 | crack( message, sessionID ); 44 | std::cout << std::endl << "IN: " << message << std::endl; 45 | } 46 | 47 | void Application::toApp(FIX::Message& message, 48 | const FIX::SessionID& sessionID ) 49 | throw(FIX::DoNotSend) 50 | { 51 | try 52 | { 53 | FIX::PossDupFlag possDupFlag; 54 | message.getHeader().getField( possDupFlag ); 55 | if ( possDupFlag ) throw FIX::DoNotSend(); 56 | } 57 | catch ( FIX::FieldNotFound& ) {} 58 | 59 | std::cout << std::endl 60 | << "OUT: " << message << std::endl; 61 | } 62 | 63 | void Application::onMessage 64 | ( const FIX50::ExecutionReport&, const FIX::SessionID& ) {} 65 | void Application::onMessage 66 | ( const FIX50::OrderCancelReject&, const FIX::SessionID& ) {} 67 | 68 | void Application::run() 69 | { 70 | while ( true ) 71 | { 72 | try 73 | { 74 | char action = queryAction(); 75 | 76 | if ( action == '1' ) 77 | queryEnterOrder(); 78 | else if ( action == '2' ) 79 | queryCancelOrder(); 80 | else if ( action == '3' ) 81 | queryReplaceOrder(); 82 | else if ( action == '4' ) 83 | queryMarketDataRequest(); 84 | else if ( action == '5' ) 85 | break; 86 | } 87 | catch ( std::exception & e ) 88 | { 89 | std::cout << "Message Not Sent: " << e.what(); 90 | } 91 | } 92 | } 93 | 94 | void Application::queryEnterOrder() 95 | { 96 | int version = queryVersion(); 97 | std::cout << "\nNewOrderSingle\n"; 98 | FIX::Message order; 99 | 100 | switch ( version ) { 101 | case 50: 102 | order = queryNewOrderSingle50(); 103 | break; 104 | default: 105 | std::cerr << "No test for version " << version << std::endl; 106 | break; 107 | } 108 | 109 | if ( queryConfirm( "Send order" ) ) 110 | FIX::Session::sendToTarget( order ); 111 | } 112 | 113 | void Application::queryCancelOrder() 114 | { 115 | int version = queryVersion(); 116 | std::cout << "\nOrderCancelRequest\n"; 117 | FIX::Message cancel; 118 | 119 | switch ( version ) { 120 | case 50: 121 | cancel = queryOrderCancelRequest50(); 122 | break; 123 | default: 124 | std::cerr << "No test for version " << version << std::endl; 125 | break; 126 | } 127 | 128 | if ( queryConfirm( "Send cancel" ) ) 129 | FIX::Session::sendToTarget( cancel ); 130 | } 131 | 132 | void Application::queryReplaceOrder() 133 | { 134 | int version = queryVersion(); 135 | std::cout << "\nCancelReplaceRequest\n"; 136 | FIX::Message replace; 137 | 138 | switch ( version ) { 139 | case 50: 140 | replace = queryCancelReplaceRequest50(); 141 | break; 142 | default: 143 | std::cerr << "No test for version " << version << std::endl; 144 | break; 145 | } 146 | 147 | if ( queryConfirm( "Send replace" ) ) 148 | FIX::Session::sendToTarget( replace ); 149 | } 150 | 151 | void Application::queryMarketDataRequest() 152 | { 153 | int version = queryVersion(); 154 | std::cout << "\nMarketDataRequest\n"; 155 | FIX::Message md; 156 | 157 | switch (version) { 158 | case 50: 159 | md = queryMarketDataRequest50(); 160 | break; 161 | default: 162 | std::cerr << "No test for version " << version << std::endl; 163 | break; 164 | } 165 | 166 | FIX::Session::sendToTarget( md ); 167 | } 168 | 169 | FIX50::NewOrderSingle Application::queryNewOrderSingle50() 170 | { 171 | FIX::OrdType ordType; 172 | 173 | FIX50::NewOrderSingle newOrderSingle( 174 | queryClOrdID(), querySide(), 175 | FIX::TransactTime(), ordType = queryOrdType() ); 176 | 177 | newOrderSingle.set( FIX::HandlInst('1') ); 178 | newOrderSingle.set( querySymbol() ); 179 | newOrderSingle.set( queryOrderQty() ); 180 | newOrderSingle.set( queryTimeInForce() ); 181 | if ( ordType == FIX::OrdType_LIMIT || ordType == FIX::OrdType_STOP_LIMIT ) 182 | newOrderSingle.set( queryPrice() ); 183 | if ( ordType == FIX::OrdType_STOP || ordType == FIX::OrdType_STOP_LIMIT ) 184 | newOrderSingle.set( queryStopPx() ); 185 | 186 | queryHeader( newOrderSingle.getHeader() ); 187 | return newOrderSingle; 188 | } 189 | 190 | FIX50::OrderCancelRequest Application::queryOrderCancelRequest50() 191 | { 192 | FIX50::OrderCancelRequest orderCancelRequest( queryOrigClOrdID(), 193 | queryClOrdID(), querySide(), FIX::TransactTime() ); 194 | 195 | orderCancelRequest.set( querySymbol() ); 196 | orderCancelRequest.set( queryOrderQty() ); 197 | queryHeader( orderCancelRequest.getHeader() ); 198 | return orderCancelRequest; 199 | } 200 | 201 | FIX50::OrderCancelReplaceRequest Application::queryCancelReplaceRequest50() 202 | { 203 | FIX50::OrderCancelReplaceRequest cancelReplaceRequest( 204 | queryOrigClOrdID(), queryClOrdID(), 205 | querySide(), FIX::TransactTime(), queryOrdType() ); 206 | 207 | cancelReplaceRequest.set( FIX::HandlInst('1') ); 208 | cancelReplaceRequest.set( querySymbol() ); 209 | if ( queryConfirm( "New price" ) ) 210 | cancelReplaceRequest.set( queryPrice() ); 211 | if ( queryConfirm( "New quantity" ) ) 212 | cancelReplaceRequest.set( queryOrderQty() ); 213 | 214 | queryHeader( cancelReplaceRequest.getHeader() ); 215 | return cancelReplaceRequest; 216 | } 217 | 218 | FIX50::MarketDataRequest Application::queryMarketDataRequest50() 219 | { 220 | FIX::MDReqID mdReqID( "MARKETDATAID" ); 221 | FIX::SubscriptionRequestType subType( FIX::SubscriptionRequestType_SNAPSHOT ); 222 | FIX::MarketDepth marketDepth( 0 ); 223 | 224 | FIX50::MarketDataRequest::NoMDEntryTypes marketDataEntryGroup; 225 | FIX::MDEntryType mdEntryType( FIX::MDEntryType_BID ); 226 | marketDataEntryGroup.set( mdEntryType ); 227 | 228 | FIX50::MarketDataRequest::NoRelatedSym symbolGroup; 229 | FIX::Symbol symbol( "LNUX" ); 230 | symbolGroup.set( symbol ); 231 | 232 | FIX50::MarketDataRequest message( mdReqID, subType, marketDepth ); 233 | message.addGroup( marketDataEntryGroup ); 234 | message.addGroup( symbolGroup ); 235 | 236 | queryHeader( message.getHeader() ); 237 | 238 | std::cout << message.toXML() << std::endl; 239 | std::cout << message.toString() << std::endl; 240 | 241 | return message; 242 | } 243 | 244 | void Application::queryHeader( FIX::Header& header ) 245 | { 246 | header.setField( querySenderCompID() ); 247 | header.setField( queryTargetCompID() ); 248 | 249 | if ( queryConfirm( "Use a TargetSubID" ) ) 250 | header.setField( queryTargetSubID() ); 251 | } 252 | 253 | char Application::queryAction() 254 | { 255 | char value; 256 | std::cout << std::endl 257 | << "1) Enter Order" << std::endl 258 | << "2) Cancel Order" << std::endl 259 | << "3) Replace Order" << std::endl 260 | << "4) Market data test" << std::endl 261 | << "5) Quit" << std::endl 262 | << "Action: "; 263 | std::cin >> value; 264 | switch ( value ) 265 | { 266 | case '1': case '2': case '3': case '4': case '5': break; 267 | default: throw std::exception(); 268 | } 269 | return value; 270 | } 271 | 272 | int Application::queryVersion() 273 | { 274 | return 50; 275 | } 276 | 277 | bool Application::queryConfirm( const std::string& query ) 278 | { 279 | std::string value; 280 | std::cout << std::endl << query << "?: "; 281 | std::cin >> value; 282 | return toupper( *value.c_str() ) == 'Y'; 283 | } 284 | 285 | FIX::SenderCompID Application::querySenderCompID() 286 | { 287 | std::string value; 288 | std::cout << std::endl << "SenderCompID: "; 289 | std::cin >> value; 290 | return FIX::SenderCompID( value ); 291 | } 292 | 293 | FIX::TargetCompID Application::queryTargetCompID() 294 | { 295 | std::string value; 296 | std::cout << std::endl << "TargetCompID: "; 297 | std::cin >> value; 298 | return FIX::TargetCompID( value ); 299 | } 300 | 301 | FIX::TargetSubID Application::queryTargetSubID() 302 | { 303 | std::string value; 304 | std::cout << std::endl << "TargetSubID: "; 305 | std::cin >> value; 306 | return FIX::TargetSubID( value ); 307 | } 308 | 309 | FIX::ClOrdID Application::queryClOrdID() 310 | { 311 | std::string value; 312 | std::cout << std::endl << "ClOrdID: "; 313 | std::cin >> value; 314 | return FIX::ClOrdID( value ); 315 | } 316 | 317 | FIX::OrigClOrdID Application::queryOrigClOrdID() 318 | { 319 | std::string value; 320 | std::cout << std::endl << "OrigClOrdID: "; 321 | std::cin >> value; 322 | return FIX::OrigClOrdID( value ); 323 | } 324 | 325 | FIX::Symbol Application::querySymbol() 326 | { 327 | std::string value; 328 | std::cout << std::endl << "Symbol: "; 329 | std::cin >> value; 330 | return FIX::Symbol( value ); 331 | } 332 | 333 | FIX::Side Application::querySide() 334 | { 335 | char value; 336 | std::cout << std::endl 337 | << "1) Buy" << std::endl 338 | << "2) Sell" << std::endl 339 | << "3) Sell Short" << std::endl 340 | << "4) Sell Short Exempt" << std::endl 341 | << "5) Cross" << std::endl 342 | << "6) Cross Short" << std::endl 343 | << "7) Cross Short Exempt" << std::endl 344 | << "Side: "; 345 | 346 | std::cin >> value; 347 | switch ( value ) 348 | { 349 | case '1': return FIX::Side( FIX::Side_BUY ); 350 | case '2': return FIX::Side( FIX::Side_SELL ); 351 | case '3': return FIX::Side( FIX::Side_SELL_SHORT ); 352 | case '4': return FIX::Side( FIX::Side_SELL_SHORT_EXEMPT ); 353 | case '5': return FIX::Side( FIX::Side_CROSS ); 354 | case '6': return FIX::Side( FIX::Side_CROSS_SHORT ); 355 | case '7': return FIX::Side( 'A' ); 356 | default: throw std::exception(); 357 | } 358 | } 359 | 360 | FIX::OrderQty Application::queryOrderQty() 361 | { 362 | long value; 363 | std::cout << std::endl << "OrderQty: "; 364 | std::cin >> value; 365 | return FIX::OrderQty( value ); 366 | } 367 | 368 | FIX::OrdType Application::queryOrdType() 369 | { 370 | char value; 371 | std::cout << std::endl 372 | << "1) Market" << std::endl 373 | << "2) Limit" << std::endl 374 | << "3) Stop" << std::endl 375 | << "4) Stop Limit" << std::endl 376 | << "OrdType: "; 377 | 378 | std::cin >> value; 379 | switch ( value ) 380 | { 381 | case '1': return FIX::OrdType( FIX::OrdType_MARKET ); 382 | case '2': return FIX::OrdType( FIX::OrdType_LIMIT ); 383 | case '3': return FIX::OrdType( FIX::OrdType_STOP ); 384 | case '4': return FIX::OrdType( FIX::OrdType_STOP_LIMIT ); 385 | default: throw std::exception(); 386 | } 387 | } 388 | 389 | FIX::Price Application::queryPrice() 390 | { 391 | double value; 392 | std::cout << std::endl << "Price: "; 393 | std::cin >> value; 394 | return FIX::Price( value ); 395 | } 396 | 397 | FIX::StopPx Application::queryStopPx() 398 | { 399 | double value; 400 | std::cout << std::endl << "StopPx: "; 401 | std::cin >> value; 402 | return FIX::StopPx( value ); 403 | } 404 | 405 | FIX::TimeInForce Application::queryTimeInForce() 406 | { 407 | char value; 408 | std::cout << std::endl 409 | << "1) Day" << std::endl 410 | << "2) IOC" << std::endl 411 | << "3) OPG" << std::endl 412 | << "4) GTC" << std::endl 413 | << "5) GTX" << std::endl 414 | << "TimeInForce: "; 415 | 416 | std::cin >> value; 417 | switch ( value ) 418 | { 419 | case '1': return FIX::TimeInForce( FIX::TimeInForce_DAY ); 420 | case '2': return FIX::TimeInForce( FIX::TimeInForce_IMMEDIATE_OR_CANCEL ); 421 | case '3': return FIX::TimeInForce( FIX::TimeInForce_AT_THE_OPENING ); 422 | case '4': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CANCEL ); 423 | case '5': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CROSSING ); 424 | default: throw std::exception(); 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /tradeclient/Application.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | /**************************************************************************** 4 | ** Copyright (c) quickfixengine.org All rights reserved. 5 | ** 6 | ** This file is part of the QuickFIX FIX Engine 7 | ** 8 | ** This file may be distributed under the terms of the quickfixengine.org 9 | ** license as defined by quickfixengine.org and appearing in the file 10 | ** LICENSE included in the packaging of this file. 11 | ** 12 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | ** 15 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 16 | ** 17 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 18 | ** not clear to you. 19 | ** 20 | ****************************************************************************/ 21 | 22 | #ifndef TRADECLIENT_APPLICATION_H 23 | #define TRADECLIENT_APPLICATION_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | class Application : 40 | public FIX::Application, 41 | public FIX::MessageCracker 42 | { 43 | public: 44 | void run(); 45 | 46 | private: 47 | void onCreate( const FIX::SessionID& ) {} 48 | void onLogon( const FIX::SessionID& sessionID ); 49 | void onLogout( const FIX::SessionID& sessionID ); 50 | void toAdmin( FIX::Message&, const FIX::SessionID& ) {} 51 | void toApp( FIX::Message&, const FIX::SessionID& ) 52 | throw( FIX::DoNotSend ); 53 | void fromAdmin( const FIX::Message&, const FIX::SessionID& ) 54 | throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon ) {} 55 | void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID ) 56 | throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType ); 57 | 58 | void onMessage( const FIX50::ExecutionReport&, const FIX::SessionID& ); 59 | void onMessage( const FIX50::OrderCancelReject&, const FIX::SessionID& ); 60 | 61 | void queryEnterOrder(); 62 | void queryCancelOrder(); 63 | void queryReplaceOrder(); 64 | void queryMarketDataRequest(); 65 | 66 | FIX50::NewOrderSingle queryNewOrderSingle50(); 67 | FIX50::OrderCancelRequest queryOrderCancelRequest50(); 68 | FIX50::OrderCancelReplaceRequest queryCancelReplaceRequest50(); 69 | FIX50::MarketDataRequest queryMarketDataRequest50(); 70 | 71 | void queryHeader( FIX::Header& header ); 72 | char queryAction(); 73 | int queryVersion(); 74 | bool queryConfirm( const std::string& query ); 75 | 76 | FIX::SenderCompID querySenderCompID(); 77 | FIX::TargetCompID queryTargetCompID(); 78 | FIX::TargetSubID queryTargetSubID(); 79 | FIX::ClOrdID queryClOrdID(); 80 | FIX::OrigClOrdID queryOrigClOrdID(); 81 | FIX::Symbol querySymbol(); 82 | FIX::Side querySide(); 83 | FIX::OrderQty queryOrderQty(); 84 | FIX::OrdType queryOrdType(); 85 | FIX::Price queryPrice(); 86 | FIX::StopPx queryStopPx(); 87 | FIX::TimeInForce queryTimeInForce(); 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /tradeclient/Makefile: -------------------------------------------------------------------------------- 1 | 2 | MF= Makefile 3 | 4 | CC= g++ 5 | 6 | CFLAGS=-I$(HOME)/local_software/include 7 | LFLAGS=-L$(HOME)/local_software/lib -lquickfix 8 | PREPROC= 9 | 10 | EXE= prog 11 | SRC= Application.cpp \ 12 | tradeclient.cpp 13 | 14 | OBJ= $(SRC:.cpp=.o) 15 | 16 | INC= 17 | 18 | .SUFFIXES: 19 | .SUFFIXES: .cpp .o 20 | 21 | all: $(EXE) 22 | 23 | .cpp.o: 24 | $(CC) $(CFLAGS) $(PREPROC) -c $< 25 | 26 | $(EXE): $(OBJ) 27 | $(CC) $(CFLAGS) -o $@ $(OBJ) $(LFLAGS) 28 | 29 | $(OBJ): $(SRC) $(INC) $(MF) 30 | 31 | clean: 32 | rm -f *.o $(EXE) core 33 | 34 | relink: 35 | rm -f $(EXE) 36 | $(MAKE) 37 | 38 | run: 39 | ./prog 40 | 41 | -------------------------------------------------------------------------------- /tradeclient/tradeclient.cfg: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | ConnectionType=initiator 3 | ReconnectInterval=60 4 | FileStorePath=store 5 | FileLogPath=log 6 | StartTime=00:00:00 7 | EndTime=00:00:00 8 | UseDataDictionary=Y 9 | DataDictionary=../spec/FIX50SP2.xml 10 | HttpAcceptPort=9911 11 | 12 | # standard config elements 13 | 14 | [SESSION] 15 | # inherit ConnectionType, ReconnectInterval and SenderCompID from default 16 | BeginString=FIXT.1.1 17 | DefaultApplVerID=FIX.5.0 18 | SenderCompID=CLIENT1 19 | TargetCompID=ORDERMATCH 20 | SocketConnectHost=127.0.0.1 21 | SocketConnectPort=5002 22 | HeartBtInt=30 23 | TransportDataDictionary=../spec/FIXT11.xml 24 | AppDataDictionary=../spec/FIX50.xml 25 | 26 | -------------------------------------------------------------------------------- /tradeclient/tradeclient.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Copyright (c) quickfixengine.org All rights reserved. 3 | ** 4 | ** This file is part of the QuickFIX FIX Engine 5 | ** 6 | ** This file may be distributed under the terms of the quickfixengine.org 7 | ** license as defined by quickfixengine.org and appearing in the file 8 | ** LICENSE included in the packaging of this file. 9 | ** 10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12 | ** 13 | ** See http://www.quickfixengine.org/LICENSE for licensing information. 14 | ** 15 | ** Contact ask@quickfixengine.org if any conditions of this licensing are 16 | ** not clear to you. 17 | ** 18 | ****************************************************************************/ 19 | 20 | #include "quickfix/FileStore.h" 21 | #include "quickfix/SocketInitiator.h" 22 | #include "quickfix/SessionSettings.h" 23 | #include "Application.h" 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | int main( int argc, char** argv ) 31 | { 32 | if ( argc != 2 ) 33 | { 34 | std::cout << "usage: " << argv[ 0 ] 35 | << " FILE." << std::endl; 36 | return 0; 37 | } 38 | std::string file = argv[ 1 ]; 39 | 40 | try 41 | { 42 | FIX::SessionSettings settings( file ); 43 | 44 | Application application; 45 | FIX::FileStoreFactory storeFactory( settings ); 46 | FIX::SocketInitiator initiator( application, storeFactory, settings ); 47 | 48 | initiator.start(); 49 | application.run(); 50 | initiator.stop(); 51 | 52 | return 0; 53 | } 54 | catch ( std::exception & e ) 55 | { 56 | std::cout << e.what(); 57 | return 1; 58 | } 59 | } 60 | --------------------------------------------------------------------------------