The HistoryReplay sample demonstrates how to use FIXHistoricalApplication to reconstruct the historical order flow from the historical persistence log.
HistoryReplay sample has less than 100 total lines of code. It can reconstruct the intra-day order flow from multiple processes within one single application. A simple "for-loop" can enumerate the entire order flow stored in a collection in memory.
The command line arguments of the HistoryReplay process is very straightforward. Apart from the access information to the repository server and the location of the FIX log directory, at least one name of the FIX engine persistence is required.
For more information about the FIX engine persistence file, please read the chapter "Persistence Files".
A sample command line argument is shown below:
HistoryReplay "qwrp://127.0.0.1:60000" "administrator" "" "C:\Temp\FIXLog" "20081130.Engine.Tutorial_OrderMan_Client" "20081130.Engine.Tutorial_OrderMan_Server"
The above command will load the intraday order flow of two processes "Tutorial_OrderMan_Client" and "Tutorial_OrderMan_Server", of the date 20081130.
The program can also be used to load several days worth of order flow of the same FIX engine.
For more information, please read "FIXHistoricalApplication".
using System; using System.Collections.Generic; using System.Text; using Teraspaces.QWFramework.Logging; using Teraspaces.QWFIX; using Teraspaces.QWFIX.Application; using Teraspaces.QWFIX.OrderManager; using Teraspaces.QWFIX.Schema; namespace HistoryReply { class Program { static void PrintUsage() { Console.Error.WriteLine("Usage:"); Console.Error.WriteLine("HistoryReply RepositoryUri RepositoryUserName RepositoryPassword LogDir EnginePersistenceName1 [EnginePersistenceName2 ...]"); } static void Main(string[] args) { if (args.Length < 5) PrintUsage(); else { // Initially "ApplicationLog.Default" is a "ConsoleApplicationLog". // We change it to "DummyApplicationLog" so that the output screen won't be messed up. ApplicationLog.Default = new DummyApplicationLog(); // We allocate 500MB for FIX message cache. Modifying this value may affect the performance. FIXEngine.InitMessageCache(FIXEngineMessageCacheType.ManageCacheByMemoryUsage, 500); FIXEngine[] engines = new FIXEngine[args.Length - 4]; FIXHistoricalApplication application; try { application = new FIXHistoricalApplication( args[0], args[1], args[2]); for (int i = 4; i < args.Length; i++) { FIXEngine curEngine = application.AddFIXEngine(args[i], args[3]); FIXOrderManager.AddFIXEngine(curEngine, application.VisualLambdaLoader); foreach (FIXSession curSession in curEngine.Sessions) { FIXSessionOrderManager curSessionOM = FIXOrderManager.GetSessionOrderManager(curSession); if (curSessionOM != null) // Order management is supported on this session curSessionOM.QueryRestatedGTOrder += new QueryRestatedGTOrderHandler(SessionOM_QueryRestatedGTOrder); } engines[i - 4] = curEngine; } for (int i = 0; i < engines.Length; i++) application.Replay(engines[i]); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); PrintUsage(); return; } foreach (FIXEngine curEngine in engines) { foreach (FIXSession curSession in curEngine.Sessions) { FIXSessionOrderManager curSessionOM = FIXOrderManager.GetSessionOrderManager(curSession); if (curSessionOM != null) { foreach (FIXSessionOrderList curOrderList in curSessionOM.SessionOrderLists) { Console.Out.WriteLine(string.Format("Persistence={0} RegularOrderCount={1} ListOrderCount={2} CrossOrderCount={3}", curOrderList.SessionPersistence.PersistenceName, curOrderList.RegularOrders.Count, curOrderList.ListOrders.Count, curOrderList.CrossOrders.Count)); } } } } application.Close(); } } static bool SessionOM_QueryRestatedGTOrder(FIXMessage executionMessage, FIXEngineMessageHandlerStatus status, out FIXOrderType fixOrderType) { // Note in this demo we assume every execution with unknown ClOrdID is a restated GT order. FIXVersion fixVersion = executionMessage.MessageComponentSchema.Schema.FIXVersion; bool ret = false; if (fixVersion.Major == 4 && fixVersion.Minor <= 1) ret = true; else ret = (executionMessage.GetCharValue(FIXConstants.Tags.ExecType) == FIXConstants.ExecTypes.Restated); fixOrderType = FIXOrderType.Single; if (ret) { if (executionMessage.ContainsTag(FIXConstants.Tags.CrossID)) fixOrderType = FIXOrderType.CrossPopulated; else if (executionMessage.ContainsTag(FIXConstants.Tags.ListID)) fixOrderType = FIXOrderType.ListPopulated; } return true; } } }