Skip to content

Instantly share code, notes, and snippets.

@elvinio
Created February 25, 2015 09:59
Show Gist options
  • Save elvinio/b0d840ddc6d50d5dc07d to your computer and use it in GitHub Desktop.
Save elvinio/b0d840ddc6d50d5dc07d to your computer and use it in GitHub Desktop.
Audit Report Generator in haskell
import Prelude hiding (lookup)
import Data.Map (Map)
import qualified Data.Map as Map
import System.IO
import Data.List
import Data.List.Split
msgType = Map.fromList [("D", "NEW ORDER"), ("G", "MODIFY"), ("F", "CANCEL"), ("8", "EXECUTION"), ("9", "CANCEL"), ("i", "MASS QUOTE"), ("r", "QUOTE REQUEST"), ("b", "QUOTE ACK"), ("c", "SECURITY DEFINITION")]
ordStatus = Map.fromList [("0", "NEW ORDER ACK"), ("1", "PARTIAL FILL"), ("2", "COMPLETE FILL"), ("4", "CANCEL ACK"), ("5", "MODIFY ACK"), ("8", "ORDER REJECTED"), ("C", "EXPIRED"), ("H", "TRADE CANCEL")]
ordType = Map.fromList [("1", "MKT"), ("2", "LMT"), ("3", "STP"), ("4", "STP-LMT"), ("K", "MKT-LMT")]
timeInForce = Map.fromList [("0", "DAY"), ("1", "GTC"), ("6", "GTD"), ("3", "FAK")]
buysell = Map.fromList [("1", "B"), ("2", "S")]
syminfo = Map.fromList [("0", ["200", "207", "461"])]
ignoreMsgType = ["0", "1", "2", "4", "5", "r", "b", "A"]
cmeTag = ["S", "52", "1028", "207", "D", "50", "7928", "1", "49", "11", "37", "35", "39", "378", "58", "54", "38", "210", "107", "55", "200", "461", "44", "99", "31", "40", "59", "9702", "204"]
header = "Server Transaction Number, Server Datetime, Manual Order Identifier, Exchange Code, Message Direction, Tag 50 ID, SMP ID, Account Number, Session ID, Executing Firm, Client Order ID, Host Order Number, Message Type, Order Status,Execution Restatement Reason, Reason Code, Buy/Sell, Quantity, Max Show, Instrument Description, Product Code, Maturity Date, CFI Code, Limit Price, Stop Price, Fill Price, Order Type, Order Qualifier, Customer Type Indicator, Origin, Give-up Firm, Give-up Indicator"
main = do
putStrLn header
handle <- openFile "current.log" ReadMode
contents <- hGetContents handle
symbol <- openFile "symbols.csv" ReadMode
symbolContent <- hGetContents symbol
mapM_ (parseSymbol) $ lines symbolContent
putStrLn $ unlines $ map (fixOutput) $ lines contents
hClose handle
parseSymbol :: String -> Maybe a
parseSymbol input =
let
fields = splitOn "," input
firstChar = head $ head fields
securityID = head $ drop 1 fields
tag200 = head $ drop 4 fields
tag207 = head $ drop 13 fields
tag461 = head $ drop 14 fields
in
if firstChar == "#"
then Nothing
else Map.insert securityID [tag200, tag207, tag461] syminfo
fixOutput :: String -> String
fixOutput input =
let
timeMessage = splitOn " : " input
fixMsgTags = splitOn "\1" $ last timeMessage
fixMsgDict = Map.fromList (map (\a -> splitFixTag a) fixMsgTags)
shortTags = foldr (\x acc -> parseTag x fixMsgDict : acc) [] cmeTag
result = concat (intersperse "," shortTags)
in result
splitFixTag :: String -> (String, String)
splitFixTag input =
let fixTag = splitOn "=" input
in (head fixTag, last fixTag)
parseTag :: String -> Map.Map String String -> String
parseTag tag fixMsgDict =
let v = Map.findWithDefault "" tag fixMsgDict
in case tag of
"35" ->
if v == "9"
then
let tag434 = Map.findWithDefault "" "434" fixMsgDict
in case tag434 of
"2" -> "MODIFY"
"1" -> "CANCEL"
else Map.findWithDefault "" v msgType
"39" ->
let msgtype = Map.findWithDefault "" "35" fixMsgDict
in
if msgtype == "9" then "REJECTED"
else Map.findWithDefault "" v ordStatus
"59" -> Map.findWithDefault "" v timeInForce
"40" -> Map.findWithDefault "" v ordType
"54" -> Map.findWithDefault "" v buysell
"D" -> if v == "O" then "To CME" else "From CME"
"49" -> let
direction = Map.findWithDefault "" "D" fixMsgDict
senderCompID = init $ Map.findWithDefault "" "49" fixMsgDict
targetCompID = init $ Map.findWithDefault "" "56" fixMsgDict
in
if direction == "O"
then take 3 senderCompID ++ "," ++ drop 3 senderCompID
else take 3 targetCompID ++ "," ++ drop 3 targetCompID
"38" -> let
msgtype = Map.findWithDefault "" "35" fixMsgDict
ordstatus = Map.findWithDefault "" "39" fixMsgDict
lastshares = Map.findWithDefault "" "32" fixMsgDict
in
if msgtype == "8" && ordstatus /= "0" && ordstatus /= "8"
then lastshares
else v
_ -> v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment