Modelling)Front-Running)in)High-Frequency)Trading) " " Written"by"Aman"Chopra" Supervised"by"Dr."Chris"C."Clack" " BSc."Computer"Science"–"COMP3091" " 1st"May"2015" " " " " " " "

Abstract) " Michael"Lewis"strongly"insinuates"that"the""market"is"“rigged”"for"the" benefit"of"highLfrequency","in"his"book"entitled"‘Flash"Boys’.""He"makes"the" claim"that"their"ability"to""ahead"of"other"traders,"which"he"calls"‘frontL running’,"by"using"faster"connections"to"stock"exchanges"and"lowLlatency"trading" algorithms"gives"them"an"unfair"advantage,"guaranteeing"profit."In"reality,"frontL running"is"difficult"to"carry"out"successfully"in"a"free"and"open"market." " This"paper"outlines"the"conditions"required"for"a"frontLrunning"highLfrequency" trader"to"make"a"profit"or"a"loss,"and"the"variables"involved."AgentLbased" simulation"is"used"to"model"each"scenario"and"detail"the"events"that"occur," leading"up"to"the"eventual"outcome." " " " " " " "

This report is submitted as part requirement for the BSc Degree in Computer Science at UCL. It is substantially the result of my own work except where explicitly indicated in the text.

The report may be freely copied and distributed provided the source is explicitly acknowledged.

1" Modelling)Front-Running)in)High-Frequency)Trading)...... )1" Abstract)...... )1" 1." Introduction)...... )4" 1.1." Flash"Boys"...... "4" 1.2." Disagreement"...... "4" 1.3." Project"Proposal"...... "4" 1.4." Aims"...... "5" 1.5." Objectives"...... "6" 2." Background)...... )7" 2.1." FrontLRunning"...... "7" 2.1.1." Exchanges-and-Order-Books-...... -7" 2.1.2." Market-Orders-and-Limit-Orders-...... -8" 2.1.3." Front=Running-Example-...... -8" 2.2." The"Existing"Simulator"...... "9" 2.2.1." Test-Harness-...... -10" 2.2.2." Agents-...... -10" 2.2.3." Messages-...... -10" 2.2.4." Exchange-...... -11" 3." Analysis)of)the)Problem)...... )13" 3.1." Assumptions"...... "13" 3.2." Delays"in"Detail"...... "14" 3.2.1." Minimal-Working-Setup-...... -14" 3.2.2." Delay-Dependencies-...... -14" 3.2.3." Historical-View-of-Data-...... -14" 3.2.4." Symmetrical-vs.-Asymmetrical-Delays-...... -15" 3.3." Multiple"Brokers"...... "15" 3.3.1." Determining-Order-Source-...... -15" 3.3.2." Pricing-Interference-...... -15" 3.4." Multiple"FrontLRunners"...... "15" 3.4.1." Front=Running-Other-Front=runners-...... -16" 3.4.2." Race-to-Order-First-...... -16" 3.5." Multiple"Brokers"and"FrontLrunners"...... "16" 4." Design)...... )17" 4.1." Delays"...... "17" 4.1.1." Minimal-Working-Setup-...... -17" 4.1.2." Delay-Dependencies-...... -18" 4.1.3." Historical-View-of-Data-...... -18" 4.1.4." Symmetrical-vs.-Asymmetrical-Delays-...... -20" 4.2." Multiple"Brokers"...... "20" 4.2.1." Determining-Order-Source-...... -20" 4.2.2." Pricing-Interference-...... -21" 4.3." Multiple"FrontLrunners"...... "22" 4.3.1." Front=runners-Closer-to-One-Exchange-...... -22" 4.3.2." Front=runners-Closer-to-Different-Exchanges-...... -23" 4.4." Multiple"Brokers"and"FrontLrunners"...... "23" 5." Implementation)...... )25" 5.1." Agents"and"Messages"...... "25" 5.1.1." Message-Types-...... -25" 5.1.2." Exchange-...... -26" 5.1.3." Broker-...... -26"

2" 5.1.4." Front=runner-...... -26" 5.1.5." Delay-...... -30" 5.1.6." Trader-...... -31" 5.2." Testing"...... "31" 5.2.1." Compilation-...... -31" 5.2.2." Command=line-Output-...... -31" 5.2.3." Trace-file-...... -32" 5.2.4." Heap-Profiling-...... -32" 6." Results)...... )34" 6.1." Delays"...... "34" 6.1.1." Minimal-Working-Setup-...... -34" 6.1.2." Delay-Dependencies-...... -36" 6.1.3." Historical-View-of-Data-...... -37" 6.1.4." Symmetrical-vs.-Asymmetrical-Delays-...... -37" 6.2." Multiple"Brokers"...... "38" 6.2.1." Determining-Order-Source-...... -38" 6.2.2." Pricing-Interference-...... -39" 6.3." Multiple"FrontLrunners"...... "50" 6.3.1." Front=runners-Closer-to-One-Exchange-...... -50" 6.3.2." Closer-to-Different-Exchanges-...... -53" 6.4." Multiple"Brokers"and"FrontLrunners"...... "54" 7." Summary)...... )56" 7.1." Summary"...... "56" 7.2." Conclusion"...... "57" 7.3." Further"Work"...... "58" 8." Appendix)...... )59" 8.1." References"...... "59" 8.2." Relevant"Simulator"Code"...... "60" 8.2.1." Frontrunner.hs-...... -60" 8.2.2." Broker.hs-...... -63" 8.2.3." Agent.hs-Snippet-...... -65" 8.2.4." Messages.hs-...... -67" 8.2.5." TestHarness.hs-Snippet-...... -69" 8.2.6." Comm.hs-Snippets-...... -70" 8.2.7." Delay.hs-...... -71" 8.2.8." Sim_orderlist.hs-...... -72" 8.2.9." MyTrader.hs-...... -75" 8.2.10." Makefile-...... -77" 8.2.11." Main.hs-...... -77" 8.2.12." Nicemime.hs-(the-exchange)-Snippet-...... -77" 8.3." User"Manual"...... "83" 8.3.1." Compilation-...... -83" 8.3.2." Running-an-Experiment-...... -83" 8.3.3." Altering-the-Variables-of-an-experiment-...... -83" 8.4." System"Manual"...... "87" 8.4.1." Creating-a-New-Experiment-...... -87" 8.4.2." Creating-a-New-Agent-...... -87" 8.5." Testing"and"Relevant"Results"...... "89" 8.5.1." Testing-...... -89" 8.5.2." Referenced-Results-...... -97" 8.6." Project"Plan"...... "101"

3" 1. Introduction) 1.1. Flash)Boys) " In"2009,"it"was"estimated"that"highLfrequency"trading"firms"accounted"for"over" 70%"of"all"U.S."equity"trading"volume"[1]."Following"the"Flash"Crash"of"2010,"highL frequency"trading"(HFT)"became"the"subject"of"much"controversy,"and"of"Michael" Lewis’"2014"novel"‘Flash"Boys’."It"tells"the"story"of"how"the"protagonist"and"his" team"create"a"new"exchange,"where"highLfrequency"traders"are"not"given"the" apparent"unfair"advantages"that"he"describes"throughout"the"book."One"of"these" being"that"their"faster"connection"speeds"to"the"exchanges"allows"them"to" effectively"predict"some"of"the"orders"that"are"sent"to"them,"meaning"that"they" can"make"a"profit"by"ordering"ahead"of"the"incoming"orders."" - “A-small-class-of-insiders-with-the-resources-to-create-speed-were-now-allowed-to- preview-the-market-and-trade-on-what-they-had-seen.”-–-Michael-Lewis,-Flash-Boys- [2]- - Here,"Lewis"is"referring"to"a"trading"technique"that"he"calls"‘frontLrunning’.- " 1.2. Disagreement) " Lewis"paints"a"picture"that"demonises"frontLrunners"that"use"these"techniques," suggesting"that"their"profits"result"from"an"unpreventable"hold"they"have"on"the" exchanges,"caused"by"a"lack"of"regulation." " “Every-systemic-market-injustice-arose-from-some-loophole-in-a-regulation-created- to-correct-some-prior-injustice.”-–-Michael-Lewis,-Flash-Boys-[3]- " With"several"European"countries"seeking"a"ban"on"HFT"in"2012"[4],"there"is"a" worry"that"the"opportunities"for"HFTs"to"frontLrun"orders"could"be"misconstrued" by"writers"to"seem"in"abundance"and"easily"taken."As"Peter"Kovac"points"out"in" his"published"rebuttal,"aptly"named"‘Flash"Boys:"Not"So"Fast’,"Lewis"gives" minimal"evidence"to"support"his"views"and"fails"to"show"that"they"are"shared"by" any"experienced"highLfrequency"traders"(HFTs)"themselves." " After"understanding"the"specifics"of"frontLrunning"explained"in"Section"2.1.1," even"from"a"theoretical"standpoint"it"is"plain"to"see"where"the"problems"could"lie" in"carrying"out"frontLrunning,"with"so"many"other"trades"being"executed"at"the" same"time." " 1.3. Project)Proposal) " This"project"was"proposed"not"only"to"shed"some"light"on"the"difficulties"of"frontL running,"but"also"to"categorise"and"define"the"problems"that"occur"when"doing" so."To"dispel"the"notion"that"frontLrunning,"using"advantages"listed"in"Flash"Boys,"

4" is"riskLfree"and"is"due"to"loopLholes"in"trading"regulations"that"need"closing,"the" following"null"hypothesis"must"be"disproven:" " High=frequency-traders-have-an-unfair-position,-allowing-them-to-front=run-brokers- to-gain-guaranteed,-risk=free-profits.- - The"plan"is"to"model"situations"where"frontLrunning"fails,"and"to"analyse"the" measured"outcomes"and"key"events"to"determine"the"exact"cause"of"the"issues." By"setting"up"simple"scenarios"to"isolate"the"problematic"combination"of" components"in"an"agentLbased"system,"we"could"step"through"each"experiment" to"find"the"theoretical"results"and"derive"mathematical"formulae"to"show"the" conditions"needed"for"frontLrunning"to"work,"how"the"values"relate"to"each"other," and"why." " As"the"experiments"become"more"complicated,"this"method"will"become" increasingly"more"difficult,"timeLcostly"and"prone"to"errors."This"is"why"these" experiments"have"been"simulated"with"a"computer."A"Haskell"stock"exchange" simulator"was"ported"from"an"existing"Miranda"one"used"in"previous"projects" that"would"be"suitable"for"these"experiments." " 1.4. Aims)) " This"project"aims"to"explore"the"phenomena"that"Michael"Lewis"describes"in" Flash"Boys"by"using"agentLbased"simulation"to"debunk"the"above"null"hypothesis." To"do"this,"the"existing"Haskell"simulator"must"be"debugged"and"extended"to"add" extra"components"needed"to"run"the"frontLrunning"experiments,"including" brokers,"frontLrunners"and"delays."" " Furthermore,"it"should"be"extended"in"a"way"that"would"allow"others"that"utilise" the"simulator"to"run"the"existing"experiments"with"different"parameters,"add" existing"agents"to"create"their"own"experiments,"and"create"their"own"agents"to" test"for"other"phenomena"easily."A"modular"design"makes"setting"up"experiments" simple,"giving"the"ability"to"select"any"components"needed"and"having"them" work"automatically"with"each"other." " Once"each"experiment"has"been"designed"and"the"simulations"have"been"run,"the" results"will"be"analysed"to"see"when"the"frontLrunners"make"a"profit"and"when" they"make"a"loss."The"details"of"each"case"will"be"studied"further"to"discover"the" reasons"behind"these"net"profits"and"defining"the"conditions"that"lead"to"them." The"relationship"between"the"variables"of"the"experiment"and"the"results"can" then"be"formularised." " If"the"reasons"behind"frontLrunner"losses"are"preventable,"then"further"results" can"be"produced"using"improved"versions"of"the"frontLrunning"algorithm"in"an" effort"to"guarantee"profit."This"way,"if"a"conceivable"method"of"eliminating"losses" is"possible,"the"final"algorithm"will"resemble"it." " "

5" " " " 1.5. Objectives)

1.5.1. )Objective)1) " i. Analyse"the"simulator"to"create"a"list"of"known"problems." ii. For"each"problem,"find"a"way"to"solve"it"or"avoid"it." "

1.5.2. Objective)2) " i. Analyse"the"simulator"to"create"a"list"of"required"additional" functions"needed"to"set"up"frontLrunning"experiments." ii. Implement"each"required"function." "

1.5.3. Objective)3) " i. Design"each"agent"as"a"wrapper"function"to"ensure"a"modular" design,"where"added"agents"can"be"added"easily"in"the"future." ii. Contain"all"experiment"variables"in"one"module"that"the"tester"can" use"to"run"their"own"experiments." "

1.5.4. Objective)4) " i. Create"a"list"of"null"hypothesises"for"each"situation"where"it"may"be" possible"for"frontLrunning"to"be"unsuccessful." ii. Design"an"experiment"for"each"hypothesis"to"test"whether"it"is" correct"or"not."" "

1.5.1. Objective)5) " i. For"each"experiment,"analyse"the"results"to"conclude"whether"the" hypothesis"is"correct"or"not." ii. Formulise"each"conclusion"and"apply"it"to"the"experiment"carried" out."

6" 2. Background) " “Someone-out-there-was-using-the-fact-that-stock-market-orders-arrived-at-different- times-at-different-exchanges-to-front=run-orders-from-one-market-to-another.”-–- Michael-Lewis,-Flash-Boys-[5]- - In"order"to"model"the"frontLrunning"scenarios"that"Michael"Lewis"suggests"is" happening,"the"mechanism"by"which"it"happens"needs"to"be"clarified." 2.1. Front-Running) " To"simulate"frontLrunning"in"Haskell,"the"process"of"frontLrunning"in"highL frequency"trading"and"the"financial"constructs"involved"must"be"defined."

2.1.1. Exchanges)and)Order)Books) " A"stock"exchange"is"a"marketplace"for"people"to"buy"and"sell"company"," shares"and"other"securities."Each"exchange"has"an"order"book"with"two"lists"of" prices,"each"priceLpoint"contains"another"list"of"orders"at"that"price,"as"shown"in" Figure"1."The"list"of"orders"at"each"priceLpoint"is"sorted"by"the"time"that"the" exchange"received"them,"where"the"oldest"orders"are"matched"first."These"limit" orders"are"placed"by"traders"to"either"buy"or"sell"stock." " One"list"contains"the"limit"orders"of"traders"who"would"like"to"sell"their"stock"at"a" particular"price,"and"these"are"called"‘offers’"or"‘asks’."The"other"list"contains"the" limit"orders"for"traders"looking"to"buy"stock"at"a"particular"price,"and"these"are" called"‘bids’."

" Figure-1.-Schematic-of-a-limit-order-book."[6]"

7" " " If"there"is"an"ask"on"the"order"book"that"has"a"lower"price"than"a"bid"on"the"order" book,"then"this"is"called"a"‘crossed"book’."Some"exchanges"do"not"accept"orders" that"will"cross"the"book,"but"some"exchanges"will"just"execute"a"trade"by" matching"the"crossed"ask"and"bid"orders"with"each"other,"which"is"called" ‘uncrossing’"the"book."Generally,"there"is"a"gap"between"the"highest"bid"price"and" the"lowest"ask"price,"called"the"‘bidLask"spread’." " An"exchange"will"constantly"publish"market"data,"which"includes"the"limit"order" book,"containing"both"the"bid"and"ask"order"lists."The"market"data"also"contains" the"size"and"price"of"every"trade"that"is"executed"on"the"exchange.""However,"the" identity"of"the"traders"involved"in"each"executed"trade,"or"the"trader"that"a"limit" order"belongs"to,"is"never"published"and"remains"anonymous." "

2.1.2. Market)Orders)and)Limit)Orders) " Limit"orders"are"sent"to"an"exchange"and"stay"on"the"order"book"until"they"are" matched"with"another"order,"which"can"be"due"to"a"crossed"book"or"a"market" order."A"market"order"has"no"price;"it"is"just"an"order"for"an"amount"of"stock"for" the"best"price"available"at"the"time"it"is"being"executed"at"the"exchange." " It"is"the"job"of"the"exchange"to"match"the"market"orders"with"the"best"price"limit" orders"in"the"order"book."For"a"buy"market"order,"it"would"match"it"with"the" lowest"priced"offers,"i.e."the"traders"offering"the"cheapest"price"for"the"stock."For" a"sell"market"order,"it"would"match"it"with"the"highest"priced"bids,"i.e."the"traders" bidding"the"highest"price"for"the"stock." " 2.1.3. Front-Running)Example)

2.1.3.1. Brokers+Splitting+Orders+ " A"stock"can"be"traded"on"many"exchanges,"and"so"logically,"exchanges"are"likely" to"have"similar"best"bid"and"best"ask"prices"to"each"other."If"there"was"a"large" difference"in"price"across"the"exchanges,"then"money"could"made"easily"by" buying"from"one"exchange"at"a"low"price"and"selling"to"the"other"exchange"at"a" high"price,"for"example." " When"a"broker"is"asked"to"buy"some"stock"on"behalf"of"a"client,"they"often"split"a" market"order"across"multiple"exchanges."This"is"so"that"the"order"is"executed"at" the"best"price"across"the"exchanges."For"example,"suppose"2"exchanges"each"have" 3"offers"on"their"books"of"size"1,"priced"at"$10,"$12"and"$14."If"the"broker"sends"a" market"order"of"size"2"to"any"single"exchange,"the"stock"will"cost"$22,"whereas"if" the"order"was"split,"with"a"market"order"of"size"1"being"sent"to"each"of"the"two" exchanges,"the"total"cost"will"be"$20." ""

8" 2.1.3.2. ++Order+Latency+ "" In"reality,"there"is"a"small"latency"of"a"few"milliseconds,"or"even"nanoseconds," between"the"time"the"broker"sends"an"order,"and"the"time"the"order"reaches"the" exchange"and"is"executed."This"is"due"to"a"number"of"factors,"including"its" physical"distance"to"the"exchange,"the"medium"by"which"the"order"is"sent"and"the" path"packets"take"through"a"network"to"reach"the"exchange." " It"is"likely"that"the"delays"between"the"broker"and"each"of"the"exchanges"are" different"from"one"another."This"means"that"if"the"broker"sends"the"orders"at"the" same"time,"one"will"arrive"at"an"exchange"first,"before"the"others"have"reached"an" exchange." "

2.1.3.3. ++Ordering+Ahead+ " Suppose"a"highLfrequency"trader"was"monitoring"the"trades"being"executed"at" each"exchange."Given"a"broker’s"tendency"to"split"its"orders"amongst"different" exchanges,"if"a"large"market"order"was"executed"at"one"of"the"exchanges,"the" likelihood"is"that"the"other"parts"of"the"order"would"soon"be"arriving"at"the"other" exchanges."So,"if"the"highLfrequency"trader"was"quick"enough,"i.e."their"latency" was"very"low,"it"could"rush"an"order"ahead"to"the"other"exchange"to"buy"the"stock" that"the"broker"was"going"to"buy,"and"offer"it"at"a"higher"price." " For"example,"suppose"again"that"there"are"2"exchanges,"each"with"3"offers"on" their"books"of"size"1,"priced"at"$10,"$12"and"$14."If"a"market"order"of"size"2" comes"in"to"one"exchange"and"matches"with"the"$10"and"$12"offers,"it"is"clear" that"another"order"of"the"same"size"must"be"coming"into"the"other"exchange"to" buy"its"$10"and"$12"offers,"otherwise,"why"was"the"first"order"not"split"across"the" exchanges?" " A"highLfrequency"trader"could"send"a"market"order"of"size"2"to"the"other" exchange,"buying"the"$10"and"$12"offers"before"the"broker’s"other"order"arrives." The"next"lowest"price"is"now"$14"at"this"exchange,"so"the"highLfrequency"trader" could"then"immediately"place"an"ask"limit"order"of"size"2"at"a"price"of"$13"each," selling"the"stock"it"just"bought"with"the"previous"market"order."This"means"that" when"the"other"part"of"the"broker’s"market"order"gets"to"this"exchange,"it"will"be" matched"with"the"highLfrequency"trader’s"offer"of"size"2"at"a"price"of"$13"each," which"is"the"best"price."The"highLfrequency"trader"bought"for"$22"and"sold"for" $26,"making"a"total"profit"of"$4."Michael"Lewis"calls"this"frontLrunning,"making" this"particular"highLfrequency"trader"a"frontLrunner." " 2.2. The)Existing)Simulator) " Much"of"the"infrastructure"and"existing"parts"of"the"simulator"can"be"utilised"to" simulate"frontLrunning."It"is"imperative"that"the"exact"function"of"these" components"is"understood"and"debugged"before"including"them"in"the" simulation.""

9" 2.2.1. Test)Harness) " Each"function"in"the"TestHarness.hs"module"is"a"single"experiment."The"tester" then"simulates"an"experiment"by"calling"one"of"the"functions"from"the" TestHarness.hs"module"in"the"Main.hs"module,"which"will"run"the"experiment" when"the"program"starts."Each"of"the"functions"in"the"TestHarness.hs"module" calls"the"simulator"function"called"‘sim’"in"Sim.hs"with"different"parameters." Included"in"these"parameters"are"the"components"of"the"experiment"that"interact" with"each"other"in"the"simulation."In"this"codebase,"they"are"referred"to"as" ‘agents’."Another"parameter"is"the"number"of"timeLsteps"the"simulation"should" run"for." "

2.2.2. Agents) " An"agent"is"a"component"of"the"experiment"and"can"be"anything,"including"stock" exchanges,"delays"or"traders."Each"agent"has"a"‘wrapper"function’"that"calls"itself" recursively."Each"time"the"wrapper"is"called"represents"a"single"unit"of" simulation"time,"which"is"referred"to"as"a"‘timeLstep’."There"are"two"key" parameters"to"this"wrapper"function."Its"first"parameter"is"the"agent’s"state," which"contains"saved"variables"from"the"previous"recursive"call"that"are"to"be" updated"and"sent"to"the"next"function"call."Its"second"parameter"is"a"list"of" messages"sent"from"other"agents"in"the"system"to"this"agent." " The"agent"uses"information"from"the"incoming"messages"together"with"its"state" information"to"output"a"list"of"messages"to"be"sent"to"other"agents.""An"agent" must"consume"a"list"of"incoming"messages"and"output"a"list"of"messages"at"each" timeLstep"for"the"recursion"to"continue"successfully."Each"agent"has"an"id" allocated"to"it"at"runtime,"which"is"used"as"an"address"by"the"messaging"system." "

2.2.3. Messages) " Messages"have"a"‘from’"and"‘to’"id,"set"by"the"agents."At"each"timeLstep,"the" simulator"begins"the"recursion"by"calling"each"agent’s"wrapper"function."It"then" takes"the"output"messages"from"each"agent,"and"uses"the"‘to’"ids"of"the"messages" to"determine"which"other"agent"to"send"each"message"to."The"messages" designated"for"a"particular"wrapper"are"added"to"its"message"list"parameter," ready"to"be"used"for"the"next"recursive"call." "

10" " " Figure-2.-Diagram-of-messaging-system" " Messages"are"used"as"a"communication"mechanism"for"the"agents"in"the"system" to"give"instructions"to"other"agents,"or"give"them"information"to"allow"them"to" perform"a"particular"function,"e.g."an"‘order"message’"can"be"sent"to"an"exchange" agent"to"execute"an"order."There"are"many"different"types"of"messages"set"up" already"that"may"be"useful"for"our"experiments." "

2.2.4. Exchange) " The"exchange"agent"reads"incoming"order"messages"and"attempts"to"execute"the" order"on"its"books,"putting"the"limit"orders"on"the"books"and"attempting"to"match" the"market"orders"with"them." " Buy"and"sell"limit"orders"can"be"of"two"types:"" " Good=til=cancelled:"It"stays"on"the"order"book"until"a"message"is"sent"to"the" exchange"to"cancel"the"order."" Good=til=date:"It"will"be"cancelled"after"a"given"expiry"date,"or"if"a"cancellation" message"is"sent"to"the"exchange." " Buy"and"sell"market"orders"can"also"be"of"two"types:" " Or=kill:"If"there"is"not"enough"liquidity"on"the"opposite"side"of"the"book,"meaning" that"the"market"order’s"size"is"bigger"than"the"total"size"of"all"the"limit"orders"on" the"books"to"match"it"against,"then"don’t"execute"the"order"at"all,"otherwise"do." And=kill:"If"there"is"not"enough"liquidity"on"the"opposite"side"of"the"book,"then" match"it"with"as"many"limit"orders"as"possible,"partly"fulfilling"the"order." " If"a"trade"is"successful,"then"acknowledgment"messages"are"sent"out"to"each"of" the"traders"involved"in"the"transaction."If"the"order"could"not"be"fulfilled"because," for"example,"there"is"no"liquidity"on"the"other"side"of"the"order"book,"then"an" error"is"given."

11" " This"exchange"will"accept"orders"that"cross"the"order"book,"and"will" subsequently"match"limit"orders"together"on"opposite"sides"of"the"book"to" uncross"them."

12" 3. Analysis)of)the)Problem) " “The-only-constraint-was-how-fast-an-electronic-signal-could-travel-between- Chicago-and-New-York—or,-more-precisely,-between-the-data-center-in-Chicago- that-housed-the-Chicago-Mercantile-Exchange-and-a-data-center-beside-the- Nasdaq’s-stock-exchange-in-Carteret,-New-Jersey.”-–-Michael-Lewis,-Flash-Boys-[7]" " Michael"Lewis"clearly"makes"very"few"assumptions"about"the"conditions"needed" for"frontLrunning"to"be"carried"out,"let"alone"the"constraints"frontLrunners"have" with"the"data"published"by"the"stock"exchanges."Once"these"assumptions"have" been"made"clear,"the"problem"can"be"analysed"to"suggest"the"experiments"that" should"be"done"to"test"whether"riskLfree"profit"can"be"made." " 3.1. Assumptions) " Assumption-1-–-Anonymous-Trades:-The-published-trade-information-is-completely- anonymous.-- " When"a"trade"is"executed"any"of"the"exchanges"Michael"Lewis"mentions"in"Flash" Boys,"only"the"traded"price"and"size"of"the"trade"are"published."This"means"that" some"extra"computation"is"needed"by"the"frontLrunner"to"guess"which"broker" sent"the"order."

" Assumption-2-=-Broker=Exchange-Delays:-The-front=runners-already-have- information-about-the-latency-between-each-broker-and-each-exchange.-- " There"is"a"delay"between"the"brokers"and"the"exchanges,"and"the"brokers"look"at" each"orderLlist"from"each"of"the"exchanges"to"determine"how"to"split"their"client’s" order,"to"get"the"best"possible"price."During"the"time"taken"for"the"orders"to"get" from"the"brokers"to"the"exchanges,"the"order"books"on"the"exchanges"may"have" changed."This"means"that"when"the"frontLrunner"sees"that"a"trade"has"been" executed"at"one"exchange,"the"orderLlist"that"the"broker"would"have"seen"at"the" time"it"sent"the"order"would"have"reached"the"frontLrunner"a"while"before."" " Therefore,"the"frontLrunner"must"keep"a"history"containing"snapshots"of"the" orderLlists"at"each"timeLstep,"and"use"the"data"to"find"out"how"the"broker"would" have"decided"to"split"the"order,"to"confirm"that"the"trade"data"matches"the" broker’s"expected"order"and"to"determine"the"correct"market"and"limit"order"size" to"send"to"the"exchange."To"find"out"how"far"back"it"must"look"in"its"orderLlist" history,"the"frontLrunner"would"have"to"know"the"size"of"the"delays"between"each" broker"and"the"exchanges,"to"determine"which"orderLlist"the"broker"would"have" seen"when"splitting"its"order." " "

13" Assumption-3-=-Order-Sizes-The-front=runner-must-know-the-total-order-size-that- the-client-instructed-the-broker-to-execute.- " The"frontLrunner"can"only"verify"that"a"particular"broker"sent"the"order"if"it" knows"the"original"client’s"order"size,"so"that"it"could"implement"the"same" algorithm"that"the"broker"uses"to"find"out"how"to"split"the"orders"amongst"the" exchanges"to"get"the"best"price."If"the"expected"order"size"matches"the"actual" order"size"from"the"trade"data,"then"that"broker"must"have"sent"the"order."If"the" expected"order"size"does"not"match"the"actual"order"size"sent"to"the"exchange," then"a"different"trader"must"have"sent"the"order." " 3.2. Delays)in)Detail) " This"section"begins"to"explore"situations"where"frontLrunning"may"not"be" successful,"under"the"assumptions"specified"in"Section"3.1"with"varying"delays" between"the"frontLrunners,"the"brokers"and"the"exchanges."The"first"part"focuses" on"problems"that"arise"when"there"is"only"one"broker,"one"frontLrunner"and"two" exchanges."

3.2.1. Minimal)Working)Setup) " Firstly,"a"simple"working"example"of"frontLrunning"needs"to"be"implemented," demonstrating"the"fundamental"conditions"needed"for"the"frontLrunner"to"make" a"profit."To"create"a"base"case"for"the"experiments,"this"example"would"have"to"be" minimised"to"show"the"very"basic"components,"conditions"and"values"needed"to" create"a"working"simulation." " Conceptually,"it"is"possible"that"the"frontLrunner"triggered"by"a"trade"made"on" one"exchange"may"not"be"quick"enough"to"order"ahead"of"the"order"going"to"the" another"exchange"before"it"arrives,"if"the"delay"between"the"broker"and"the"other" exchange"is"not"big"enough."

3.2.2. Delay)Dependencies) " Given"that"there"are"clearly"cases"where"if"the"delays"are"too"small,"then"frontL running"is"simply"not"possible,"it"is"imperative"that"data"is"collected"to"show"the" delays"required"for"a"frontLrunner"to"make"a"profit,"across"all"experiments."Using" this"data,"it"should"be"possible"to"formulate"the"relationship"between"the"delays" and"outline"their"dependencies"on"each"other"to"ensure"that"frontLrunning"is" possible"and"successful.""

3.2.3. Historical)View)of)Data) " As"explained"in"assumption"2,"a"historical"view"of"the"orderLlist"data"is"needed," due"to"the"delays"between"the"broker"and"the"exchanges."This"means"that"the" amount"of"historical"data"that"needs"to"be"indexed"depends"on"the"size"of"the" delays."It"would"be"important"to"outline"how"the"number"of"historical"orderLlist" entries"required"changes"with"the"size"of"the"delays"in"the"experiment.""

14" 3.2.4. Symmetrical)vs.)Asymmetrical)Delays) " In"some"cases,"messages"will"be"sent"biLdirectionally"between"two"agents,"e.g."the" exchange"will"send"trade"data"to"the"frontLrunner,"and"the"frontLrunner"will"send" orders"to"the"exchange."In"reality,"depending"on"a"number"of"factors"mentioned" in"Section"2.1.3.2,"the"delay"of"messages"in"one"direction"could"differ"slightly" from"the"delay"of"messages"going"in"the"other"direction."Accumulatively,"as" messages"are"sent"back"and"fourth,"it’s"possible"that"this"could"have"a"significant" effect"on"the"experiment,"and"so"this"should"be"considered"during"testing." " 3.3. Multiple)Brokers) " Adding"another"broker"introduces"more"problems"for"the"frontLrunner"in" determining"which"broker"sent"the"order,"and"if"another"broker’s"order"changes" the"market"at"an"exchange"before"the"frontLrunner’s"order"reaches"it,"the"frontL runner"could"incur"a"loss."

3.3.1. Determining)Order)Source) " As"mentioned"in"Section"3.1,"trade"data"anonymity"means"that"it"will"be"difficult" to"ascertain"which"of"the"brokers"sent"the"order."However,"the"effect"on"the" frontLrunner’s"profit"could"be"largely"unaffected,"depending"on"the"algorithm" they"use."If"they"were"to"only"target"one"of"the"brokers,"knowing"that"they"plan"to" make"a"large"order,"then"it"may"be"the"case"that"they"will"always"profit."Although," with"the"added"complexity"of"multiple"brokers,"it"is"difficult"to"tell"without" thorough"experimentation." "

3.3.2. Pricing)Interference) " While"a"frontLrunner’s"order"is"in"transit,"it’s"possible"that"the"orderLbook"at"the" exchange"could"change."This"could"happen"because,"for"example,"some"of"the" limit"orders"have"timedLout"or"are"cancelled."Furthermore,"it’s"possible"for"the" broker’s"order"in"transit"to"be"based"on"outLdated"orderLlist"data,"and"so"its" initial"market"order"could"be"executed"at"any"price,"depending"on"how"the" market"has"changed." " With"multiple"brokers"it’s"now"even"more"probable"that"the"market"at"each" exchange"will"change"and"at"a"higher"frequency,"since"other"brokers"will"also"be" making"orders"at"each"exchange"whilst"other"orders"are"in"transit."This"leads"to" even"more"uncertainty"when"frontLrunning." " 3.4. Multiple)Front-Runners) " Adding"another"frontLrunner"to"the"experiment,"rather"than"another"broker," gives"rise"to"a"different"set"of"problems,"where"frontLrunners"will"mistake" another"frontLrunner’s"order"for"a"broker’s"order,"and"only"the"first"frontL running"order"to"be"executed"will"incur"a"profit.""

15" 3.4.1. Front-Running)Other)Front-runners) " With"multiple"frontLrunners,"there"are"many"opportunities"for"frontLrunning"to" be"disrupted."With"acknowledgement"messages"being"sent"to"each"trader"after" completing"a"trade,"there"may"be"mechanisms"to"ensure"that"frontLrunners"do" not"frontLrun"their"own"orders."However,"with"multiple"frontLrunners,"there" could"be"points"at"which"one"frontLrunner’s"order"coincidently"matches"a" brokers"expected"activity."This"means"that"it"is"certainly"possible"for"frontL runners"to"frontLrun"orders"placed"by"other"frontLrunners,"who"they"mistake"for" brokers."" " There"is"also"the"possibility"that"frontLrunners"place"orders"whilst"another"frontL runner’s"order"is"in"transit,"so"that"the"market"orders"they"place"end"up"matching" another"frontLrunner’s"limit"order,"instead"of"the"broker’s.""

3.4.2. Race)to)Order)First) " If"frontLrunner"1"is"close"to"one"exchange,"i.e."the"latency"is"small,"and"frontL runner"2"is"closer"to"another,"then"although"frontLrunner"1"may"have"received" trade"data"triggering"it"to"frontLrun"first,"frontLrunner"2’s"frontLrunning"order" may"actually"reach"the"exchange"first."In"this"case,"the"first"frontLrunner"to"detect" the"broker’s"order"first"is"not"necessarily"the"one"that"makes"a"profit"from"frontL running." " " 3.5. Multiple)Brokers)and)Front-runners) " This"experiment"models"a"realistic"stock"exchange"setup,"which"will"introduce"a" mixture"of"the"scenarios"mentioned"in"the"sections"above."This"will"give"us"a" more"comprehensive"look"at"the"likelihood"of"frontLrunners"making"a"profit"and" which"scenarios"will"guarantee"a"profit,"if"at"all."We"can"then"suggest"changes"to" the"frontLrunning"algorithm"to"isolate"the"examples"where"the"frontLrunners"do" make"a"profit,"in"an"attempt"to"ascertain"whether"there"can"be"an"algorithm"that" proves"Michael"Lewis"right,"and"guarantees"a"profit.

16" 4. Design)) " Now"that"some"possible"disequilibrium"conditions"have"been"considered,"the" experiment"setups"can"be"designed"in"detail."Visualising"each"scenario"in"this" way"will"help"to"generate"meaningful"null"hypothesises,"and"make"some" predictions"based"on"the"key"variables"that"change." 4.1. )Delays) " The"first"setup"to"consider"is"one"with"only"1"frontLrunner"and"1"broker." "

4.1.1. Minimal)Working)Setup)

" Figure-3.-Diagram-for-proposed-minimal-working-setup.-" "

δ! = !!,!!!δ! = !!,!!!δ! = δ! = ! δ! = 1, !δ!! = ! δ!!!" " The"broker"B1"can"send"orders"via"the"delays"δ!"and!δ!"to"exchanges"X1"and"X2," respectively."FrontLrunner"1"has"two"servers,"and"each"are"very"close"to"different" exchanges,"as"they"would"be"in"real"highLfrequency"trading"scenario."Server"1" monitors"broadcasted"order"lists"and"trade"data"from"exchange"X1,"and"server"2" monitors"broadcasts"from"exchange"X2."As"specified"in"the"quote"from"Flash" Boys"at"the"start"of"Section"3,"the"two"servers"have"a"very"high"speed"connection" between"them,"represented"by"delays"δ!"and"δ!!."This"is"why"it"is"quicker"for"X2’s" trade"data"to"reach"server"1"via"server"2,"rather"than"directly"to"server"1,"and"vice" versa,"meaning"that"the"frontLrunners"use"this"link"to"send"the"trade"data"to"each" other."

17" " Setting"up"the"experiment"shown"in"Figure"3"will"determine"the"minimum"delay" sizes"required"to"create"a"working"frontLrunning"example."Theoretically,"this" should"be"the"smallest"number"of"components"needed"to"construct"a"base"case" for"frontLrunning."It"may"seem"trivial"to"determine"the"delay"sizes"required"for" successful"frontLrunning"using"this"diagram,"but"there"may"be"a"number"of" variables"that"are"introduced"by"using"the"simulator,"e.g."there"may"be"a"transit" delay"of"messages"being"sent"from"one"component"to"the"delay"component"itself," adding"more"timeLsteps." " This"is"why"it"is"best"to"leave"all"specific"calculations"and"derivations"until"after" the"implementation"and"testing"stages."Although"at"this"stage,"a"series"of" hypothesises"could"be"devised"for"the"outcome"of"scenarios"that"could"affect"the" frontLrunner’s"profit." " NULL-HYPOTHESIS-1-–-The-front=runner-will-make-a-profit,-regardless-of-the- latency-between-the-broker-and-the-exchanges.- -

4.1.2. Delay)Dependencies) " With"this"initial"setup,"by"incrementally"changing"the"values"of"the"delays"and" recording"the"frontLrunner’s"profit,"the"direct"impact"of"the"delay"sizes"on"the" frontLrunner’s"profit"will"be"clear."If"there"is"a"relationship"between"the"two,"then" this"could"be"made"explicit"by"using"a"formula"to"show"how"they"are"related." "" NULL-HYPOTHESIS-2-=-There-will-be-no-minimum-difference-necessary-in-the-delay- between-the-broker-and-each-exchange-for-front=running-to-be-successful.- -

4.1.3. Historical)View)of)Data) " Since"there"are"only"ever"two"exchanges,"it"follows"that"each"frontLrunner"would" only"need"to"calculate"two"values"to"be"used"as"the"index"into"the"orderLlist" history"for"each"exchange"to"find"the"orderLlist"seen"by"the"broker"at"the"time"it" issued"its"orders."These"values"are"labelled"as"‘’"for"the"frontLrunner’s"local" exchange"and"‘’"for"the"other"exchange"in"the"simulation."By"stepping" through"an"example"simulation,"we"can"determine"how"far"back"to"look"in"the" orderLlist"history:" " For"example,"for"frontLrunner"1"L"server"2"(FR1LS2):" " Relative(Time( Event( Lδ!!" X2"broadcasts"its"bid"and"ask"order"books"L"these"will"be" received"by"B1"at"time"0" Lδ!!"+"δ!" FR1LS2"receives"X2's"order"books"sent"at"time"Lδ!!" Lδ!!"+"δ!"+"δ!" FR1LS1"receives"X2's"order"books"sent"at"time"Lδ!!"(via" FR2)" Lδ!!" X1"broadcasts"its"bid"and"ask"order"books"L"these"will"be"

18" received"by"B1"at"time"0" Lδ!!"+"δ!" FR1LS1"receives"X1's"order"books"sent"at"time"Lδ!!" Lδ!!"+"δ!"+"δ!!" FR1LS2"receives"X1's"order"books"sent"at"time"Lδ!!" 0" B1"sends"two"market"orders"(to"X1"and"X2)"based"on"the" most"recent"order"books"received"from"X1"and"X2" δ!" X1"receives"B1'a"market"order,"executes"the"order,"and" broadcasts"the"trade"data" δ!"+"δ!" FR1LS1"receives"trade"data"from"X1"and"forwards"it"to" FR1LS2" δ!"+"δ!"+"δ!!"" FR1LS2"receives"X1's"trade"data"(via"FR1),"calculates" whether"front"running"is"possible,"and"if"so"sends"one" market"order"and"one"limit"order"to"X2" δ!"+"δ!"+"δ!!+"δ!!" X2"receives"FR1LS2's"two"orders,"both"of"which"are" executed" δ!" X2"receives"B1's"market"order,"executes"the"order,"and" broadcasts"the"trade"data" " When"FR1LS2"receives"X1's"trade"data"at"time"(δ1"+"δ2"+"δ3b)"it"assumes"it"to"be" due"to"a"market"order"sent"by"B1"at"time"0;"and"it"assumes"the"market"order"was" based"on"the"latest"X1"and"X2"order"book"information"available"to"B1"at"time"0."" These"were"the"order"books"sent"by"X1"at"time"(Lδ1b)"and"by"X2"at"time"(Lδ5b)," and"these"two"order"books"were"received"by"FR1LS2"respectively"at"times"(Lδ1b"+" δ2"+"δ3b)""and"(Lδ5b"+"δ4)." " When"FR1LS2"calculates"whether"a"frontLrunning"opportunity"is"available,"it"will" compare"the"trade"data"for"the"market"order"just"executed"on"X1"with"the"X1"and" X2"order"books"at"the"time"B1"sent"that"market"order.""If"FR1LS2"receives"the" trade"data"at"time"X,"then"FR1LS2"must"look"in"its"historical"order"book"data"to" find"the"X1"order"books"it"received"at"time"(XL((δ1"+"δ2"+"δ3b)"L"(Lδ1b"+"δ2"+" δ3b))"and"the"X2"order"books"it"received"at"time"(X"L"((δ1"+"δ2"+"δ3b)"L"(Lδ5b"+" δ4))." " Given"that"frontLrunners"will"always"frontLrun"orders"in"transit"to"their"local" exchange,"and"are"therefore"triggered"by"orders"at"the"other"exchange,"the"values" of"alpha"and"beta"are"related"to"the"delay"values"as"such:" " FR1LS1"α"="δ!! −!δ! +!δ! +!δ! +!δ!" FR1LS2"α"=!δ! +!δ! +!δ!! −!δ! +!δ!!" " FR1LS1"β"=!δ! + δ!!" FR1LS2"β"="δ! + δ!!!" "

With"symmetrical"delays,"where"!δ!! = ! δ!:" " FR1LS1"α"="δ! −!δ! +!δ! +!δ! +!δ!" FR1LS2"α"="δ! +!δ! +!δ! −!δ! +!δ!" " FR1LS1"β"=!δ! + δ!!"

19" FR1LS2"β"="δ! + δ!!!" " " This"setup"could"also"be"used"to"incrementally"change"the"values"of"the"delays"to" record"the"effect"it"has"on"the"indexing"of"historical"orderLlist"data."These"values" of"alpha"and"beta"would"need"to"be"calculated"for"each"broker"in"the"simulation." ""

4.1.4. Symmetrical)vs.)Asymmetrical)Delays) " There"should"also"be"simulations"involving"all"combinations"of"delay"sizes" individually,"depending"on"which"direction"the"messages"are"being"sent"between" each"pair"of"components,"i.e."!δ!! ≠ δ!."If"there"is"a"fundamental"difference" between"having"asymmetrical"delays"and"symmetrical"delays,"then"the" experiments"should"each"be"repeated"with"different"values"of"δ!!delays"as"well"as" δ!"delays,"where"the"key"delays"that"affect"the"experiment"are"varied." " 4.2. Multiple)Brokers) " This"experiment"will"show"the"added"complexity"of"introducing"another"broker" to"the"simulation."

4.2.1. Determining)Order)Source)

- Figure-4.-Diagram-of-proposed-setup-for-multiple-brokers." " A"simulation"should"be"carried"out"that"introduces"another"broker,"but"where" only"the"alpha"and"beta"values"for"the"first"broker"are"calculated,"as"in"the" previous"experiment."This"will"help"to"highlight"the"problems"that"adding" another"broker"causes,"by"looking"through"the"trace"files"step"by"step."Another" simulation"should"then"be"carried"out"where"values"of"alpha"and"beta"are"

20" calculated"for"each"of"the"brokers,"to"see"whether"the"frontLrunner"can"frontLrun" orders"from"multiple"brokers"and"whether"this"introduces"any"unforeseen" problems." " NULL-HYPOTHESIS-3-–-The-front=runner-will-be-able-to-successfully-front=run-both- the-of-brokers’-orders-without-calculating-new-values-of-alpha-and-beta-for-each- broker.- "

4.2.2. Pricing)Interference)) "

δ! = !! + !,!!!δ! = !! + !,!!!δ! = δ! = ! δ! = δ! = ! δ! = 1, !δ!! = ! δ!!!" " and" "

δ! = !! + !,!!!δ! = !! + !,!!!δ! = ! δ! = δ! = ! δ! = δ! = 1, !δ!! = ! δ!!!" " where"k"is"the"minimum"delay"discussed"in"Section"4.1.2,"which"may"or"may"not" be"zero." " After"verifying"that"the"frontLrunner"can"correctly"frontLrun"at"least"one"of"the" brokers,"their"profit"needs"to"be"compared"with"scenarios"where"even"though"the" correct"frontLrunning"order"has"been"sent"to"an"exchange,"the"frontLrunning" execution"is"affected"by"price"changes"in"the"market."The"set"of"these"scenarios" that"we"are"particularly"interested"in"are"ones"in"which"orders"placed"by"other" traders"are"affecting"the"market"at"each"exchange,"and"thus"disrupting"the"frontL running"process." "" NULL-HYPOTHESIS-4-–-Front=running-will-be-successfully-carried-out,-regardless-of- the-time-between-the-first-and-second-brokers-sending-their-orders.------

21" 4.3. Multiple)Front-runners) " By"instead"adding"another"frontLrunner,"other"issues"surface."

" Figure-5.-Diagram-of-proposed-setup-for-multiple-front=runners.- -"

4.3.1. Front-runners)Closer)to)One)Exchange) " δ! = !!!,!!!δ! = !!!,!!!δ! = ! δ!!,!!!δ! = ! δ!!,!!!δ! = ! δ! = δ! = 1!,!!!" "

δ! = ! δ! + !"# δ! + !δ! + δ!!, δ! + δ! +!δ! + !9,"!δ!! = ! δ!" " " The"frontLrunners"will"execute"the"same"initial"trade"as"the"brokers"they"plan"to" frontLrun."This"experiment"might"result"in"infinite"frontLrunning,"with"one"frontL runner"mistaking"another’s"order"for"a"broker’s"order,"beginning"a"cycle"of"frontL runners"frontLrunning"each"other’s"orders." " This"problem"will"occur"in"any"experiment"with"multiple"frontLrunners"and"will" need"to"be"addressed"in"the"frontLrunner’s"algorithm"to"achieve"meaningful" results,"rather"than"an"endless"chain"of"frontLrunning."Once"this"phenomenon"is" prevented,"results"from"both"this"and"the"following"experiment"can"be"used"to" observe"the"race"for"frontLrunners"to"place"their"orders"first." "

22" NULL-HYPOTHESIS-5-–-Front=runner’s-will-not-front=run-another-front=runner’s- order.- -

4.3.2. Front-runners)Closer)to)Different)Exchanges) " δ! = !!!,!!!δ! = !!!,!!!δ! = ! δ! = δ! = δ! = δ! = 1!,!!!" "

δ! = ! δ! + !"# δ! + !δ! + δ!!, δ! + δ! +!δ! + !9,"!δ!! = ! δ!" " This"experiment"could"yield"examples"where"the"first"frontLrunners"to"detect" frontLrunning"opportunities"using"trade"data"are"not"necessarily"the"ones"to" profit"from"issuing"frontLrunning"orders." " NULL-HYPOTHESIS-6-–-The-first-front=runners-that-receive-the-trade-data-will- always-be-the-first-front=runners-to-successfully-front=run-the-broker’s-order,-and- make-a-profit.- - 4.4. Multiple)Brokers)and)Front-runners) " Finally,"this"experiment"attempts"to"amalgamate"all"the"previous"disequilibrium" conditions"by"having"both"2"frontLrunners"and"2"brokers."

" Figure-6.-Diagram-of-proposed-setup-for-multiple-front=runners-and-brokers." "

δ! = !!!,!!!δ! = !!!,!!!δ! = δ! = δ! = δ! = 1!, δ! = δ! = 5, !δ!! = ! δ!!!!"

23" " δ! = ! δ! + !"# δ! + !δ! + δ!!, δ! + δ! +!δ! + !9," " δ! = ! δ! + !"# δ! + !δ! + δ!!, δ! + δ! +!δ! + !9" " This"is"an"experiment"to"produce"a"set"of"data"in"accordance"with"the"conclusions" reached"from"previous"experiments."Drawing"a"hypothesis"for"the"outcome"of" this"experiment"is"inconceivable"at"this"stage,"and"depends"largely"on"the"result" of"simpler"simulations."

24" 5. Implementation) " Now"begins"the"debugging"and"extension"of"the"existing"Haskell"simulator." 5.1. Agents)and)Messages) " Although"the"infrastructure"for"agents"and"the"messaging"system"has"already" been"made,"there"are"still"many"new"agents"to"add."The"existing"messaging" system"must"also"be"extended"to"support"that"types"of"trade"data"that"is"required" for"the"experiments."

5.1.1. Message)Types) " Each"agent"has"an"id"allocated"to"it,"which"are"increasing"integers"indexed"from"1," since"the"simulator"itself"is"given"the"id"0."The"ids"of"the"agents"are"allocated" according"to"the"order"they"appear"in"the"list"of"agents,"in"the"test"harness’" experiment"function,"i.e."agents"="[agentWithId1,"agentWithId2,"agentWithId3]." This"feature"had"already"been"implemented"in"the"existing"codebase."These"ids" are"used"as"addresses"for"the"simulator’s"messaging"system"to"ensure"that"each" message"is"sent"to"the"correct"agent." "

5.1.1.1. Order+Messages+ " These"are"messages"destined"for"exchanges,"and"they"contain"an"order"to" execute."The"order"data"has"a"‘type’,"which"for"market"orders"would"be"‘Buy" AndKill’"or"‘Sell"AndKill’,"since"in"these"experiments"there"is"no"need"to"use"an" order"of"type"‘OrKill’."For"limit"orders,"the"type"would"be"‘Offer"GoodTilCancelled’" or"‘Bid"GoodTilCancelled’,"since"in"these"experiments"‘GoodTilDate’"will"not"be" needed." " The"order"data"also"contains"the"size"of"the"order,"its"price"and"the"time"at"which" it"was"received"by"the"exchange,"which"is"L1"by"default"and"is"changed"once"it" arrives"at"an"exchange."Order"messages"existed"in"the"original"code"base"and" have"not"been"changed"or"extended." "

5.1.1.2. Broadcast+Messages+ " Broadcasts"are"a"type"of"message"that"is"sent"to"every"agent"in"the"simulation," regardless"of"its"‘to’"id"value."The"broadcast"types"have"been"extended,"so"that" now"they"can"carry"orderLlist"data"or"trade"data,"so"that"the"exchange"can"use" broadcasts"to"send"order"list"and"trade"data"to"the"frontLrunners"and"brokers." "

5.1.1.3. Trade+Messages+ "

25" Trade"messages"are"sent"as"confirmations"that"a"trade"has"been"successful,"and"is" sent"to"both"parties"involved"in"the"transaction."They"contain"the"order"data"for" both"the"orders"that"were"matched"with"each"other." " " "

5.1.2. Exchange) " Only"two"exchanges"are"needed"for"any"of"the"experiments,"since"introducing"any" more"exchanges"may"increase"the"complexity"of"the"simulation,"but"would"not" provide"any"further"insight"into"how"frontLrunning"is"affected."The"exchange"has" now"been"extended"to"broadcast"its"‘bids’"orderLlist,"‘asks’"orderLlist"and"trade" data"of"all"trades"executed"at"each"timeLstep." "

5.1.3. Broker) " Whether"the"broker"is"attempting"to"buy"or"sell"will"not"make"a"difference"within" the"context"of"what"is"being"shown"in"this"simulation."So"to"simplify"the" experiment,"the"broker"is"only"to"issue"buy"market"orders,"and"so"only"the"‘asks’" orderLlist"from"each"exchange"is"relevant"to"them."Once"the"broker"receives"a" populated"‘asks’"orderLlist"from"each"exchange,"it"compares"them"to"find"which" has"the"best"price,"which"in"this"case"would"be"the"cheapest"price."It"then" removes"the"order"with"the"best"prices"from"its"copy"of"the"orderLlist,"and"adds" the"size"of"the"order"to"an"accumulator"for"the"exchange"that"the"orderLlist"came" from,"as"shown"in"Figure"7." "

" " Figure-7.-Code-snippet-of-broker’s-order-size-determination-algorithm." " This"process"is"continued"recursively,"passing"an"updated"copy"of"the"orderLlist," with"its"order"removed,"and"the"accumulator"to"itself,"until"the"total"accumulated" size"for"both"exchanges"reaches"the"client’s"expected"original"order"size,"i.e."‘size’." This"process"gives"the"size"of"the"two"orders"that"the"broker"would"need"to"send" to"the"exchanges"to"get"the"best"possible"price"for"the"client’s"total"order."It"then" immediately"sends"these"orders"to"the"exchanges"in"the"same"timeLstep." "

5.1.4. Front-runner) " To"model"the"highLfrequency"trader"server"communications"that"would"occur"in" a"realLlife"example"of"frontLrunning,"each"frontLrunner"is"made"up"of"a"pair"of"

26" agents"referred"to"throughout"this"report"as"‘servers’."Each"server"in"the"pair" monitors"one"of"the"two"exchanges."" " Although"the"exchanges"broadcast"their"orderLlists"and"trade"data,"due"to"the" lower"latency"connection"between"the"frontLrunners,"only"the"frontLrunner’s" server"monitoring"a"particular"exchange"will"receive"the"data"and"send"it"to"the" server"monitoring"the"other"exchange,"which"decides"whether"to"order"ahead"or" not."This"means"that,"other"than"frontLrunning,"the"frontLrunner"servers"will"also" send"the"orderLlist"and"trade"data"to"the"other"server"in"the"pair,"monitoring"the" other"exchange."The"frontLrunner"server"will"then"use"this"data"and"the"data" from"its"local"exchange’s"broadcasts"to"decide"whether"to"frontLrun"an"order"on" its"way"to"its"local"exchange." " Assuming"the"frontLrunner"is"already"aware"of"the"order"size"that"the"client"has" sent"to"the"broker,"which"is"called"‘size’."If"a"server"receives"trade"data"from"the" server"monitoring"the"other"exchange,"it"uses"its"alpha"and"beta"values"to"locate" the"two"orderLlists"that"the"broker"would"have"seen"at"the"time"it"issued"the" order"that"causes"the"trade."After"locating"these"orderLlists"in"its"history,"the" server"compares"the"two"orderLlists"to"find"which"exchange"had"the"best"price."It" then"removes"the"order"with"the"best"prices"from"its"copy"of"the"orderLlist,"and" adds"the"size"of"the"order"to"an"accumulator"for"the"exchange"that"the"orderLlist" came"from." " It"continues"to"do"this"recursively,"passing"an"updated"copy"of"the"orderLlist,"with" its"order"removed,"and"the"accumulator"to"itself,"until"the"total"accumulated"size" for"both"exchanges"reaches"the"client’s"expected"original"order"size,"i.e."‘size’." This"process"mimics"the"broker"algorithm"to"give"the"size"of"the"two"orders"that" the"broker"would"have"sent"to"the"exchanges,"to"get"the"best"possible"price"for" the"client’s"original"order"size." " If"the"trade"data"from"the"other"exchange"shows"that"the"size"of"the"executed" order"matches"the"expected"order"size"that"it"has"calculated,"then"the"server"will" place"orders"to"frontLrun"the"order"that"is"on"its"way"to"the"local"exchange."If"it" does"not"match"the"order,"it"attempts"to"repeat"this"process"with"a"different" broker’s"alpha"and"beta"values,"if"there"is"another"broker." " Before"it"can"frontLrun"the"order,"it"first"needs"to"calculate"the"price"at"which"it" will"sell"the"stock"to"secure"a"profit,"and"ensure"that"the"broker’s"market"order" will"match"with"it,"by"selling"it"for"the"next"best"price."It"first"looks"at"the"latest" orderLlist"from"its"local"exchange"to"find"what"the"next"best"price"will"be"after"it" issues"its"market"order."It"does"this"by"removing"the"orders"with"the"best"prices" from"its"copy"of"the"orderLlist,"until"the"size"of"the"order"it"plans"to"place"has" been"reached."It"then"sets"the"price"of"its"offer"limit"order"one"price"‘tick’"lower" than"the"next"best"price"on"the"order"list." " The"frontLrunner"then"sends"two"orders"to"its"local"exchange,"one"buy"market" order"to"match"with"the"offer"that"the"broker’s"order"was"hoping"to"match"with," and"one"offer"limit"order"immediately"after,"set"at"the"price"it"calculated,"to"

27" replace"the"offer"that"was"there"as"the"next"best"priced"offer"on"the"orderLbook." This"algorithm"is"summarised"in"Figure"8." " "

28" " 29" " Figure-8.-Proposed-Front=running-Algorithm-Diagram-for-FR1=S2,-where-trade-data- from-X1-is-received-via-FR1=S1" " For"the"experiment"where"there"are"multiple"brokers,"alpha"and"beta"values" must"be"calculated"for"each"broker."This"also"means"that"an"orderLlist"history"for" both"exchanges"must"be"kept"for"each"broker,"where"its"length"is"determined"by" its"alpha"and"beta"values."The"best"way"to"correctly"identify"which"broker"has" sent"the"order"is"by"trying"to"run"the"frontLrunner’s"logic"mentioned"above"for" each"broker"in"the"order"of"most"orderLlist"history"required"to"the"least."This" way,"if"the"orderLlist"history"is"not"long"enough"to"index"at"alpha"and"beta,"then" that"broker"can’t"be"the"one"that"sent"the"order,"and"so"another"must"be"tried." "

" Figure-9.-Code-snippet-for-proposed-broker-identification-algorithm.- "

5.1.5. Delay) " The"delay"wrapper"has"two"parameters,"a"message"queue"and"a"delay"buffer,"and" recursively"calls"itself"like"any"other"agent"wrapper."The"buffer"is"initially"set"to" be"a"list"of"lists"of"messages,"each"containing"an"empty"message"known"as"a" ‘hiaton’,"where"the"size"of"the"list"is"the"size"of"the"delay"in"timeLsteps."The" message"queue"is"another"list"of"lists"of"messages,"which"is"initially"empty." " At"each"timeLstep,"the"list"of"incoming"agent"messages"is"added"to"the"delay" queue."The"delay"wrapper"outputs"the"list"of"messages"at"the"head"of"the"delay" buffer."If"the"message"queue"is"not"empty,"then"the"list"of"messages"at"the"head"of" the"queue"is"appended"to"the"end"of"the"delay"buffer."If"the"message"queue"is" empty,"then"a"list"containing"a"hiaton"is"appended"to"the"delay"buffer,"so"that"the" delay"buffer"size"is"always"kept"the"same,"and"has"a"size"equal"to"the"initial"length" of"the"delay." "

" Figure-10.-Pseudo=code-for-delay-design." " To"model"the"possibility"of"asymmetrical"delays"between"the"agents,"there"are" two"delay"agents"between"each"other"pair"of"agents"that"can"communicate" directly"which"each"other."Each"delay"is"responsible"for"messages"going"in"a"

30" single"direction"between"the"agents,"and"can"be"set"to"different"sizes," independently." "

5.1.6. Trader)) " A"simple"trader"has"been"created"to"send"a"set"of"initial"limit"orders"to"each" exchange"to"populate"their"orderLbooks"before"any"broker"orders"are"placed"or" frontLrunning"begins." " 5.2. Testing) " Not"only"does"the"code"each"part"of"the"simulation"need"to"be"written"and" debugged,"but"there"must"also"be"a"quick,"yet"inLdepth"method"of"testing"that"the" trading"mechanisms"are"working"as"expected."This"can"also"be"used"for" debugging,"and"later"for"generating"results."

5.2.1. Compilation) " A"makefile"is"used"to"compile"the"simulator,"which"includes"a"list"of"the"files"to"be" included"in"the"compilation,"and"the"GNU"Haskell"Compiler"command." " The"command"includes"flags"to"place"the".o"output"files"and"the".h"header"files" into"a"separate"folder"called"‘output’,"so"that"they"are"not"mixed"amongst"the" source"files." " The"software"must"be"recompiled"if"any"changes"are"made"to"the"experiments," which"is"done"by"editing"the"code." "

5.2.2. Command-line)Output) " To"debug"the"basic"experiment"and"check"that"code"was"running"correctly,"‘trace’" functions"from"the"Haskell"package"‘Debug.Trace’"were"placed"amongst"the"code" to"output"a"verbose"indication"of"the"functions"being"called"at"runtime,"and"some" critical"values"that"need"to"be"checked."" " This"helped"to"debug"a"number"of"problems,"including"one"where"the"code" execution"would"stop"at"the"frontLrunner."This"was"because"the"assumption"was" that"if"the"frontLrunner"agent"had"no"messages"to"output,"then"it"could"just" output"an"empty"list."However,"the"simulator"requires"that"each"agent"output"a" list"of"messages,"even"if"these"messages"are"empty,"and"so"instead"the"frontL runner"was"required"to"output"a"list"containing"a"hiaton"to"continue"executing" the"code."This"is"due"to"the"recursive"nature"of"the"simulator’s"infrastructure"that" waits"until"each"agent"has"output"a"list"of"messages"before"continuing." " The"commandLline"output"gives"a"summary"of"the"events"that"occur"at"each"timeL step,"without"delving"into"the"inner"workings"of"the"messaging"system."This"is" where"the"profit"for"each"frontLrunner"is"displayed"at"each"timeLstep."

31" "

5.2.3. Trace)file) " After"the"code"was"executing"correctly"and"all"runLtime"errors"were"eliminated," the"trace"file"became"the"main"debugging"tool"to"ensure"that"messages"were" being"sent"amongst"the"traders"as"expected."" " The"trace"file"gives"further"insight"into"the"events"that"occur"during"the" simulation,"including"the"individual"broadcast"and"messages"sent"between"the" agents,"and"their"content."Both"the"trace"file"and"commandLline"output"can"be" used"for"results"analysis." "

5.2.4. Heap)Profiling) " The"existing"exchange"module"required"the"most"debugging"and"the"process"of" understanding"exactly"what"it"was"doing"took"a"significant"amount"of"time."One" particularly"difficult"problem"to"solve"was,"what"was"later"discovered"to"be,"a" memory"leak."The"program"failed"to"halt,"which"the"only"indication"as"to"what" was"wrong."Since"the"exchange"was"an"integral"part"of"the"system,"pinLpointing" the"module"that"contained"the"root"of"the"problem"proved"to"be"difficult." " Running"the"program"with"a"restricted"amount"of"memory"confirmed"that"there" was"in"fact"a"memory"leak."This"was"done"by"using"the"run"command"with"these" flags:"“./Main.hs"+RTS"–M64m"–RTS”,"which"limited"amount"of"memory"to"64MB," and"the"memory"was"exhausted"quite"quickly."To"detect"the"function"causing"the" leak,"the"following"commands"were"used"to"compile"the"program"for"memory" usage"profiling"and"output"a"heap"profile"when"executing"the"program:" " ghc Main.hs -o Main -odir output -hidir output -rtsopts -prof -auto-all -caf-all

./Main +RTS –h

A"snippet"of"the"heap"profile"can"be"found"in"Section"8.5.1.1."By"running"‘hp2ps’" to"convert"the"heap"profile"into"a"PostScript"file,"the"graph"produced"in"Figure"11" made"it"clear"where"the"leak"was"occurring."

32" " - Figure-11.-The-graph-of-the-heap-profile-from-the-PostScript-file,-showing-the- memory-leak-occurring-in-the-function-‘nice_mime_emptylob”." " After"revisiting"the"function,"the"cause"of"the"memory"leak"was"clear:" " " " The"potentially"infinite"list"[0,0..]"should"have"been"an"empty"list"[],"as"the"new" experiment"required"an"iteration"over"this"list."Once"this"change"had"been"made," the"heap"profile"appeared"to"be"more"balanced,"indicated"by"the"new"PostScript" graph"in"Figure"12." " "

" " Figure-12.-The-graph-of-the-heap-profile-from-the-PostScript-file,-no-longer-showing- abnormal-memory-usage." " "

33" 6. Results) 6.1. Delays)

6.1.1. Minimal)Working)Setup) "

" Figure-13.-Minimal-setup-diagram-showing-data=flow-paths-x-and-y-for-an-example- where-!!"<"!!." " The"results"show"that"null"hypothesis"1"is"false,"and"there"must"be"a"minimum" difference"of"10"between"the"latency"of"the"broker"one"exchange,"if"all"other" delays"in"the"setup"are"of"size"1." " In"Figure"13,"path"y"shows"the"series"of"delays"involved"in"the"steps"required"for" the"frontLrunner"to"frontLrun"an"order"heading"on"path"x"to"exchange"X1.The" broker"B1"will"send"an"order"to"exchange"X1"and"exchange"X2."For"example,"if" delay"!!"is"smaller"than"!!,"the"order"to"X2"will"arrive"first."Trade"data"will"be" sent"from"X1"to"frontLrunner"server"FR1LS2"via"delay"!!,"which"will"pass"it"on"to" server"FR1LS1"via"delay"!!." " FR1LS1"will"send"a"market"order"to"X1"via"delay"!!,"and"check"its"orderLlist" history"to"determine"the"size"of"the"limit"order"to"send"to"X1,"and"it’s"most"recent" orderLlist"to"see"what"price"to"set"the"limit"order"at"to"make"a"profit."In"all"that" time,"the"broker’s"second"order"must"still"be"in"transit"on"path"x"via"!!"to"arrive" at"X1"after"FR1LS1’s"orders"reach"X1."Thus"delay"!!"must"be"significantly"larger" than"delay"!!." " "

34" )) 19" δ5+ 17" 15" 13" 11" 9"

(Ymesteps)) 7" 5" 3" 1" Broker)1)to)Exchange)2)Delay)( 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" 11" 12" 13" 14" 15" 16" 17" 18" 19" 20" Broker)1)to)Exchange)1)Delay)(δ1)) (Ymesteps))

Front1running"Unsuccessful" Front1running"Successful" " " Figure-14.-Results-graph-for-minimal-working-setup-experiment,-varying-delays- !!(x)-and-!!-(y)."Results-table-in-Section-8.5.2.2.- -

" " Figure-15.-Swim-lane-diagram-for-minimal-working-setup-experiment,-where-FR1= S1-front=runs-successfully-

35" - " Figure-16.-Swim-lane-diagram-for-minimal-working-setup-experiment,-where-FR1= S1-front=runs-unsuccessfully- "

6.1.2. Delay)Dependencies) " Given"the"logic"provided"in"the"previous"section,"we"can"go"further"to"say"that" any"added"delay"to"path"y"must"be"added"to"path"x"to"ensure"that"the"broker’s" order"does"not"arrive"at"X1"before"it"has"been"frontLrun"by"FR1LS1."Since"there"is" a"single"timeLstep"delay"between"each"agent"sending"a"message"from"one"to" another,"we"can"state"the"following"formula:" " " Σδ!"" =""Total"delay"sizes"on"path"x" Σδ!"" =""Total"delay"sizes"on"path"y" n!" =""Number"of"agents"on"path"x" n!" =""Number"of"agents"on"path"y" " " Σδ! +!n! < !Σδ! +!n!" "

36" So,"for"the"example"above:" "

δ! + !2! +!δ! + !2! +!δ! + !2! +!!δ!! + !2!! < !Σδ! + !2! " " In"the"case"of"the"results"in"Figure"14,"the"frontLrunning"has"been"successful" when"the"delays"along"path"x"are"equal"to"the"delays"along"path"y,"i.e."when"the" delay"size"is"1"from"the"broker"to"one"exchange,"and"10"for"the"other."However," the"delays"along"path"y"must"be"lessLthan,"but"not"equal"to,"the"delays"on"paths"x."" " This"is"to"ensure"that"the"broker’s"order"reaches"the"exchange"at"least"one"timeL step"after"the"frontLrunner"has"frontLrun"the"order,"because"if"the"orders"reached" the"exchange"at"the"same"time"the"result"could"be"unpredictable."Null"hypothesis" 2"is"incorrect,"and"even"though"the"results"show"that"frontLrunning"is"successful" with"a"minimum"difference"of"k=9"when"all"other"delays"are"1,"a"safer"value" would"be"k=10." "

6.1.3. Historical)View)of)Data) " The"formulae"derived"in"Section"4.1.3"have"given"accurate"results,"and"so"the" frontLrunner"servers"can"look"back"to"a"point"in"its"orderLlist"history"to"find"the" orderLlist"that"the"broker"viewed"at"the"time"it"made"its"decision"of"how"to"split" the"client’s"order"across"the"exchanges."The"formulae"clearly"state"the"exact" relationship"between"the"delays"in"the"setup"and"the"values"of"alpha"and"beta," which"the"frontLrunner"servers"can"use"as"an"index"into"their"orderLlist"history." " It"follows"that,"in"a"realLlife"frontLrunning"scenario,"the"latency"on"path"x"and" path"y"directly"affects"the"amount"of"memory"needed"for"the"frontLrunner"to" store"orderLlist"history"information,"which"could"be"considerable"given"that"each" delay"could"potentially"be"hundreds"of"milliseconds."A"frontLrunner"would"also" need"to"consider"the"timeLcost"of"a"slow"algorithm"needed"to"calculate"the"limit" order"size,"limit"order"price,"and"slow"history"search"and"memory"access.""The" more"time"wasted"in"the"steps"required"to"frontLrun"the"order,"the"more"likely"it" is"that"the"frontLrunner"will"lose"the"race"to"order"ahead"of"the"broker." "

6.1.4. Symmetrical)vs.)Asymmetrical)Delays) " To"model"a"realistic"example,"simulations"have"been"done"to"show"the"outcome" of"scenarios"where"the"delay"going"from"one"agent"to"another"is"different"from" the"delay"of"messages"going"in"the"opposite"direction." " Even"by"changing"the"delays"to"be"asymmetric,"the"system"still"works"as" expected"and"the"results"validate"the"delay"dependency"formula"above,"although" the"timings"of"the"events"that"occur"are"different."This"is"because"the"system’s" variables"are"already"dependant"on"the"different"delays"along"paths"x"and"y,"and" their"sizes."Only"the"delays"in"the"direction"of"these"paths"will"affect"the"results"of" frontLrunning,"which"is"why"the"frontLrunner’s"profits"are"the"same.""

37" " The"delays"in"the"opposite"directions"only"affect"the"latency"on"the"paths"that"the" orderLlist"data"takes,"impacting"values"of"alpha"and"beta,"which"change"according" to"the"derived"formulae"in"Section"4.1.3."This"means"that"the"system"is"virtually" the"same,"and"the"rules"of"the"system"conform"to"the"same"formulae"that"a" system"with"symmetrical"delays"would." " " 6.2. Multiple)Brokers)

6.2.1. Determining)Order)Source) " The"first"experiment"introduced"another"broker"with"the"exact"same" configuration"and"code"as"the"experiments"with"only"one"broker."The"trace"files" for"this"experiment"showed"that"the"orders"sent"from"the"second"broker"did"not" match"the"expected"orders"from"the"first"broker,"which"the"values"of"alpha"and" beta"were"configured"for,"and"so"no"frontLrunning"was"carried"out"for"these" orders."The"results"are"given"in"Figure"17." " 10" 9" 8" 7" 6" 5" 4"

(timesteps)( 3" 2" 1" 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" δ6) ( Broker(2(to(Exchange(2(Delay(( Broker(1(to(Exchange(2(Delay((δ5)( (timesteps)(

FrontLrunning"Unsuccessful" FrontLrunning"Successful" " " Figure-17.-Results-graph-for-multiple-brokers,-where-only-broker-B1-is-targeted-by- the-front=runner,-varying-delays-!!(x)-and-!!-(y)."Results-table-in-Section-8.5.2.3.1.- " " The"second"experiment"aimed"to"determine"which"broker"sent"the"order"and" frontLrun"them"accordingly,"by"using"the"algorithm"described"in"Section"5.1.4." The"results"in"Figure"18"are"evidently"more"complete"and"symmetrical,"as"the" frontLrunners"are"now"frontLrunning"both"the"broker’s"orders"successfully"by" calculating"the"values"of"alpha"and"beta"for"each,"whenever"there"is"no"pricing" interference."This"shows"that"null"hypothesis"3"is"incorrect." "

38" " 10"

δ6) ) 9" 8" 7" 6" 5"

(Ymsteps)) 4" 3" 2" 1" Broker)2)to)Exchange)2)Delay)( 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Broker)1)to)Exchange)2)Delay)(δ5)) (Ymesteps))

Front1running"Unsuccessful" Front1running"Successful" " " Figure-18.-Results-graph-for-multiple-brokers,-where-both-brokers-are-targeted-by- the-front=runner,-varying-delays-!!(x)-and-!!-(y)."Results-table-in-Section-8.5.2.3.2.- -

6.2.2. Pricing)Interference)

6.2.2.1. Brokers’+first+orders+sent+to+the+same+exchange+ "

" Figure-19.-Diagram-with-two-brokers-detailing-the-events-leading-to-pricing- interference-when-both-brokers’-first-orders-are-sent-to-exchange-X2.-

39" " From"the"results"in"Figure"20,"we"can"see"that"frontLrunning"is"not"successful" when"the"difference"between"the"two"broker"delays"is"very"small,"showing"that" null"hypothesis"4"is"incorrect."More"specifically,"the"results"show"that"if"the" difference"is"3"timeLsteps"or"less,"then"the"frontLrunner"does"not"frontLrun"both" orders"successfully." " 10"

δ6) ) 9" 8" 7" 6" 5"

(Ymsteps)) 4" 3" 2" 1" Broker)2)to)Exchange)2)Delay)( 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Broker)1)to)Exchange)2)Delay)(δ5)) (Ymesteps))

Front1running"Unsuccessful" Front1running"Successful" " " Figure-20.-Results-graph-for-multiple-brokers,-where-each-of-the-brokers’-first- orders-are-sent-to-X2,-varying-delays--!!(x)-and-!!-(y)."Results-table-in-Section- 8.5.2.3.3.- " If"B1"sends"an"order"to"X2,"the"trade"data"is"passed"from"FR1LS2"to"FR1LS1"and" the"order"is"frontLrun"at"X1"by"FR1LS1."This"changes"the"orderLlist"at"X1,"so"that" the"bestLpriced"order"is"the"limit"order"that"FR1LS1"placed"when"frontLrunning"at" X1." " However,"before"this"updated"orderLlist"information"reaches"FR1LS1,"FR1LS1"has" already"received"more"trade"data"from"FR1LS2"about"B2’s"order"at"X2."This" means"that"it"will"base"its"frontLrunning"limit"order"price"on"historic"data,"and"so" the"second"frontLrunning"attempt"does"not"make"as"much"profit"as"it"should"do." Examples"are"given"below." " "

"

40" Figure-21.-Initial-order=book-setup-for-this-experiment-where-‘myexch’-is-X1-and- ‘otherexch’-is-X2- "

" Figure-22.-Results-table-for-multiple-brokers,-varying-delays-!!(x)-and-!!-(y)."- " " With"the"initial"orderLlists"in"Figure"21,"FR1LS1’s"first"frontLrun"would"have" placed"a"market"order,"buying"at"$1998"and"placed"a"limit"order"at"$1999." B1"would"then"buy"at"$1999,"earning"FR1LS1"$50"of"profit"(($1999L$1998)"x"50)" and"raising"the"next"best"price"to"$2000."Since"FR1LS1’s"second"frontLrunning" orders"would"have"been"based"on"old"data,"it"would"also"have"placed"a"limit" order"at"$1999."Since"this"limit"order"at"$1999"is"now"the"next"best"price,"FR1L S1’s"market"order"would"buy"its"own"limit"order"at"this"price,"giving"no"profit." " When"B2’s"order"finally"arrives"at"X1,"it"buys"at"$2000,"and"since"it"has"does"not" match"with"a"frontLrunner’s"order,"because"FR1LS1’s"limit"order"is"no"longer"on" the"books,"it"signal’s"FR1LS2"to"frontLrun"the"order"and"it"frontLruns"at"X2,"buying" at"$2003"and"selling"for"$2004,"but"the"order"remains"on"the"books"with"no" buyers."This"is"why"FR1LS1’s"net"profit"is"$50"and"FR1LS2’s"profit"is"L$100150" ($2003"x"50"outLofLpocket)." " When"the"delays"are"equal,"FR1LS1’s"profit"is"$50"and"FR1LS2’s"is"$0."This"is" because,"due"the"to"way"the"system"works,"the"frontLrunners"can"only"frontLrun" one"order"at"each"timeLstep,"and"so"when"two"arrive"at"the"same"time"from"the" brokers,"only"one"frontLrunning"order"is"sent"to"the"exchange." "

41" " " Figure-23.-Swim-lane-diagram-for-multiple-brokers,-where-both-orders-are-front= run-successfully."- " " " " "

42" " " Figure-24.-Swim-lane-diagram-for-multiple-brokers,-where-both-orders-are-front= run-unsuccessfully."- " " " " "

43" The"more"random"initial"orderLlist"structure"in"Figure"25"produces"the"results"in" Figure"26,"giving"another"example"of"the"above"situation." "

" " Figure-25.-A-more-random-initial-order=book-setup-for-this-experiment-where- ‘myexch’-is-X1-and-‘otherexch’-is-X2- "

- Figure-26.-Results-table-for-this-experiment-with-a-more-random-initial-order=book- setup-list,-varying-delays-!!(x)-and-!!-(y).- " " There"is"an"argument"to"say"that"the"frontLrunner"could"just"update"its"local"copy" of"the"orderLlist"data,"by"applying"the"orders"that"it"sent"to"the"exchange"to"it’s" local"copy,"ensuring"that"its"data"always"matches"the"exchange’s."However,"as" discussed"in"Section"3.3.2,"in"a"realLlife"scenario"the"exchange’s"orderLlist"could" change"for"a"number"of"reasons"that"the"frontLrunner"may"not"be"aware"of," including"order"cancellations"and"timeouts,"and"so"a"direct"copy"of"the"data"is" required"from"the"exchange" " " " " " " "

44" 6.2.2.2. Brokers’+first+orders+sent+to+different+exchanges+ "

- Figure-27.-Diagram-with-two-brokers-detailing-the-events-leading-to-pricing- interference-when-B1’s-first-order-is-placed-at-X1-and-B2’s-first-order-is-placed-at- X2.- " 10"

δ6) ) 9" 8" 7" 6" 5"

(Ymesteps)) 4" 3" 2"

Broker)2)to)Exchange)2)Delay)( 1" 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Broker)1)to)Exchange)1)Delay)(δ1))) (Ymesteps))

Front1running"Unsuccessful" Front1running"Successful" " " - -

45" - Figure-28.-Results-graph-for-multiple-brokers,-where-B1’s-first-order-is-placed-at-X1- and-B2’s-first-order-is-placed-at-X2,-with-varying-delays-!!(x)-and-!!-(y)."Results- table-in-section-8.5.2.3.3.- " The"results"in"Figure"28"show"a"more"complex"pattern,"and"the"trace"files"explain" why."If"a"frontLrunner"server"sends"orders"to"exchange"X2"to"frontLrun"broker"B1" and"place"an"offer"at"the"next"lowest"price"P,"then"another"broker"B2"could"place" a"market"order"at"the"exchange"before"the"frontLrunner"server’s"order"arrives," increasing"the"next"best"price"at"the"exchange"to"P+X."Broker"B1’s"frontLrunning" market"order"would"then"buy"at"P+X"and"the"broker’s"offer"would"be"priced"at"P," causing"the"front"runner"to"incur"a"loss"of"X." " If"B1"orders"at"X1"and"the"trade"data"travels"from"X1"to"FR1LS2,"triggering"FR1L S2"to"frontLrun"at"X2,"and"in"the"meantime"B2"orders"at"X2,"then"if"the"updated" orderLlist"from"X2"doesn’t"reach"FR1LS2"before"FR1LS2"places"its"frontLrunning" order"at"X2,"then"this"order"will"be"placed"at"the"wrong"price,"as"it"is"based"on" historic"data."Following"this"logic,"if"FR1LS2’s"frontLrunning"order"were"to"reach" X2"before"B2’s"order"reaches"X2,"then"FR1LS2’s"order"will"be"based"on"accurate" data"and"it"will"frontLrun"successfully." "

-

46" Figure-29.-Swim-lane-diagram-for-multiple-brokers,-where-B1’s-first-order-is-placed- at-X1-and-B2’s-first-order-is-placed-at-X2,-and-both-brokers-are-front=run- successfully.- -

" " Figure-30.-Swim-lane-diagram-for-multiple-brokers,-where-B1’s-first-order-is-placed- at-X1-and-B2’s-first-order-is-placed-at-X2,-and-both-brokers-are-front=run- successfully.-

47" -

" - " Figure-31.-Swim-lane-diagram-for-multiple-brokers,-where-B1’s-first-order-is-placed- at-X1-and-B2’s-first-order-is-placed-at-X2,-and-front=running-is-unsuccessful.- -

48" Figure"29,"30"and"31"focus"on"FR1LS2’s"profit,"when"!!"<"!!,"i.e."the"topLleft"half"of" the"graph"in"Figure"28."These"results"are"reflected"in"the"line"!!"="!!,"where"FR1L S1’s"profit"is"affected"in"the"same"way." " From"all"the"experiments"involving"multiple"brokers,"the"following"condition"for" disequilibrium"can"be"stated:" " If-the-delay-until-one-broker’s-order-triggers-a-front=runner-to-front=run-at-an- exchange-is-less-than-the-delay-until-the-updated-order=list-from-another-broker’s- order-at-that-exchange-reaches-the-front=runner,-and-the-delay-until-the-front= runner’s-order-is-placed-is-greater-than-the-delay-until-a-broker-places-his-order-at- X2,-then-the-front=runner-will-not-make-a-profit.- " Given"that"there"is"an"added"delay"of"size"1"for"each"message"to"get"from"one" agent"to"another:" " Σδ!"" =""Total"delay"sizes"on"path"t" Σδ!"" =""Total"delay"sizes"on"path"u" Σδ!"" =""Total"delay"sizes"on"path"v" n!" =""Number"of"agents"on"path"t" n!" =""Number"of"agents"on"path"u" n!" =""Number"of"agents"on"path"v" " " Σδ! +!n! ! < !!Σδ! +!n! + Σδ! +!n!" AND"

Σδ! +!n! + !Σδ!! +!n!! ! > !!Σδ! +!n!" " !" "

Σδ! +!n! − !Σδ!! −!n!! ! < !!Σδ! +!n! ! < !!Σδ! +!n! + Σδ! +!n!" " " So,"in"the"above"example:" "

δ!! + !2 + δ! + 2 −!δ!! − 2!"

< ! δ!! + !2 + δ! + 2! +!δ! !+ 2! +!δ!! + 2!

! δ!! + !2 + δ! + 2 +!δ! + 2!" " " This"is"why"when"B1"is"the"first"to"order"at"X1"in"the"results"above,"FR1LS2"does" not"make"a"profit,"and"when"B2"orders"at"X2"first,"FR1LS1"does"not"make"a"profit."" Changing"the"delays"between"the"exchanges"and"each"frontLrunner"from"1"to"2" generates"the"results"in"Figure"32,"which"validates"the"formula"above." "

49" 10"

δ6) ) 9" 8" 7" 6" 5"

(Ymesteps)) 4" 3" 2"

Broker)2)to)Exchange)2)Delay)( 1" 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Broker)1)to)Exchange)1)Delay)(δ1)) (Ymesteps))

Front1running"Unsuccessful" Front1running"Successful"

" Figure-32.-Results-graph-for-multiple-brokers,-where-B1’s-first-order-is-placed-at-X1- and-B2’s-first-order-is-placed-at-X2,-with-!!-=-!!-=-2-rather-than-1,-and-varying- delays-!!(x)-and-!!-(y)."Results-table-in-section-8.5.2.3.3.- " 6.3. Multiple)Front-runners)

6.3.1. Front-runners)Closer)to)One)Exchange) "

" " Figure-33.-Diagram-with-two-front=runners-showing-the-events-that-lead-to-cyclical- front=running-and-front=runners-matching-orders-with-other-front=runners."

50" " This"experiment"should"isolate"the"frontLrunners"as"much"as"possible,"showing" their"precise"effect"on"the"other’s"trading"patterns."To"do"this,"there"are"2"frontL runners"and"1"broker"in"the"experiment,"as"shown"in"the"diagram"above."In" accordance"with"the"delay"dependency"formula,"the"delay"between"B1"and"X1" has"a"constant"size"of"1,"and"the"delay"between"B1"and"X2"changes"with"the"size" of"the"delays"between"the"frontLrunners"and"the"exchanges." " Since"the"distance"between"the"different"exchanges"is"not"the"focus"of"this" experiment,"the"size"of"the"delays"between"each"frontLrunner"server"in"a"pair"is" kept"as"1."The"size"of"the"delay"between"each"frontLrunner"in"a"pair"and"the" exchanges"is"kept"equal,"and"so"the"only"variables"in"this"experiment"are"the" delay"between"one"frontLrunner"server"pair"and"the"exchanges,"against"the"other" frontLrunner"pair"and"the"exchanges,"as"proposed"in"section"4.3.1." "

10" 9" 8" 7" 6" 5" 4" 3" Delay(( δ0) ( (timesteps)( 2" 1" 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Exchange(1(to(Front>runner(1(>(Server(1(Delay((δ1)(

Exchange(1(to(Front>runner(2(>(Server(1( (timesteps)(

FrontLrunner"4"Makes"a"Protit" FrontLrunner"2"Makes"a"Protit"

" Figure-34.-Results-graph-for-multiple-front=runners,-where-both-front=runners-are- closer-to-X1-than-X2,-with-varying-delays-!!(x)-and-!!-(y)."Results-table-in-section- 8.5.2.4.1.- " Pairs"of"frontLrunners"could"be"prevented"from"frontLrunning"their"own"orders" by"using"the"trade"messages"sent"back"to"them"to"indicate"that"the"trade"data" belongs"to"their"trade"and"not"the"broker’s,"and"so"the"frontLrunner"should"not" forward"the"trade"data"to"the"other"frontLrunner"to"trigger"frontLrunning." " However,"trades"from"other"frontLrunners"are"still"anonymous,"and"since"other" frontLrunners"will"make"the"exact"same"buy"orders"as"the"brokers"are"attempting" to"make,"there"will"be"way"to"tell"whether"a"broker"has"made"the"order,"or" another"frontLrunner"has."This"is"especially"true"when"considering"that"frontL runners"may"be"too"late,"and"rather"than"ordering"ahead"of"the"broker,"they"may" order"after"the"broker"in"a"failed"frontLrunning"attempt,"creating"even"more" uncertainty."This"means"that"although"null"hypothesis"5"is"incorrect,"there"

51" doesn’t"seem"to"be"a"way"to"prevent"cyclical"frontLrunning"entirely,"and"so"the" results"in"Figure"34"focus"on"the"profits"made"by"the"other"frontLrunner"servers" in"each"pair." " If"FR1LS1"is"slightly"less"delayed"than"FR2LS1,"then"FR1LS1"will"end"up"placing"a" market"order"to"buy"the"lowest"priced"stock,"and"then"placing"an"offer"for"the" next"lowest"price,"which"FR2LS1"will"end"up"buying"with"it’s"frontLrunning" market"order,"and"selling"again"for"the"next"lowest"price,"which"is"same"price." FR1LS1’s"order"also"triggers"FR2LS2"to"begin"frontLrunning,"since"it"thinks"that"it" is"a"broker’s"order,"and"the"other"part"of"it"is"soon"to"arrive"at"exchange"X2."" "

" " Figure-35.-Results-graph-for-multiple-front=runners,-where-both-front=runners-are- closer-to-X1-than-X2,-and-FR1=S1-makes-a-profit.- - " "

52" Certain"techniques"can"be"used"to"prevent"frontLrunners"frontLrunning"some"of" each"other’s"orders."For"example,"this"could"be"done"by"ensuring"that"only"one" frontLrunning"order"is"sent"to"an"exchange"between"any"pair"of"frontLrunners"at" any"given"time."Such"techniques"may"reduce"a"frontLrunner"pairs’"maximum" attainable"profit,"but"they"could"reduce"their"risk"of"making"losses." " The"results"in"Figure"34"clearly"indicate"that"the"frontLrunner"server"pair"that"it" closer"to"the"exchanges"frontLruns"first"and"makes"a"profit."This"is"still"the"case," regardless"of"whether"the"other"frontLrunner"in"a"pair"is"cyclically"frontLrunning" unnecessarily,"or"that"the"quickest"frontLrunner’s"profit"may"be"coming"from" other"frontLrunners’"frontLrunning"market"orders"matching"the"offers,"rather" than"market"orders"from"brokers."

)

6.3.2. Closer)to)Different)Exchanges) " " 10" 9" 8" 7" 6"

δ0) ) 5" 4" Delay)( (Ymesteps)) 3" 2" 1" 1" 2" 3" 4" 5" 6" 7" 8" 9" 10" Exchange)1)to)Front-runner)2)-)Server)1) Exchange)2)to)Front-runner)1)-)Server)2)Delay)(δ5)) (Ymesteps))

Front1runner"4"Makes"a"Profit" Front1runner"2"Makes"a"Profit" " " Figure-36.-Results-graph-for-multiple-front=runners,-where-FR2=1-is-closer-to-X1- than-FR1=S1-and-FR1=S2-is-closer-to-X2-than-FR2=S2,-with-varying-delays-!!(x)-and- !!-(y)."Results-table-in-section-8.5.2.4.2.- " When"one"frontLrunner"in"a"pair"is"closer"to"its"local"exchange"than"the"other" frontLrunner,"similar"patterns"emerge"in"the"results"where"frontLrunners"are" mistaking"market"orders"placed"by"other"frontLrunners"for"a"broker’s"order."" " It"is"still"the"case"that"the"frontLrunner"that"places"their"frontLrunning"order"at" the"exchange"the"quickest"is"the"one"to"make"a"profit."However,"the"difference" here"is"that"the"first"frontLrunner"pair"to"receive"trade"data"is"no"longer"the"pair" that"profits"from"frontLrunning,"as"their"frontLrunning"order"does"not"reach"the" exchange"first."This"means"that"null"hypothesis"6"was"also"incorrect.""

53" " No"new"scenarios"appear"to"be"surfacing,"no"matter"what"combinations"of"delays" between"the"frontLrunners"and"the"exchanges"are."This"means"that"the"following" can"be"stated:" " If-the-total-delay-for-one-front=runner-pair-to-send-a-front=running-order-is-less- than-the-total-delay-for-other-front=runners,-they-will-profit-from-front=running-the- order.- " So,"for"the"example"above,"if:" " δ! + 2 +!δ!! + 2 + !δ!! + 2! < ! δ! + 2 +!δ!! + 2 +!δ!! + 2!" " then"FR1LS2"will"make"a"profit." " 6.4. Multiple)Brokers)and)Front-runners)

" Figure-37.-Results-table-summary-for-multiple-brokers-and-front=runners,-where- both-front=runners-are-closer-to-X1-than-X2,-with-δ! = δ! = 5,!varying-delays-!!(x)- and-!!-(y),-all-other-delays-being-of-size-1."Results-table-in-Section-8.5.2.5.- " " The"seemingly"sporadic"results"in"Figure"37"are"due"to"the"fact"that"there"are" now"more"frontLrunner"orders"that"are"being"mistaken"for"broker’s"orders,"and"a" mixture"of"disequilibrium"conditions"in"the"setup,"with"multiple"brokers"and" frontLrunners."" " The"frontLrunner"makes"a"profit"when"none"of"the"disequilibrium"conditions" detailed"in"the"sections"above"are"met,"and"this"is"reflected"in"the"trace"files." However,"if"the"frontLrunners"mistake"another"frontLrunner’s"orders"for"a" broker’s"order,"or"its"orders"are"based"on"historic"data,"then"this"would"still" result"in"a"net"loss,"as"their"orders"are"left"unmatched."" "

54" Although"there"is"no"way"to"show"an"obvious"visual"pattern,"this"experiment" gives"a"broad"range"of"results"that"each"individually"align"with"the"findings"of"the" previous"experiments."

55" 7. Summary) 7.1. )Summary)

7.1.1. Objective)1:)Debugging)the)Simulator) " Many"parts"of"the"simulator"are"utilised"to"perform"the"experiments,"which"have" been"debugged"successfully"and"now"run"as"expected."Certain"functions"of"the" simulator"and"exchanges"serve"different"tests"required"by"previous"projects,"and" have"been"left"as"they"are." " Debugging"the"simulator"has"been"a"continual"process"throughout"the"project,"as" added"functions"have"introduced"the"need"for"more"changes."Moreover,"this" objective,"along"with"debugging"my"own"code,"has"been"the"most"timeL consuming"aspect"of"this"project."This"has"been"due"to"bugs"found"in"the" translation"from"the"Miranda"version"of"the"code"base,"in"previously" underutilised"properties"of"the"simulator"were"found,"which"this"project"relied" heavily"on."" "

7.1.2. Objective)2:))Add)Required)Components)to)the)Simulator) " All"necessary"components"have"been"added"to"the"simulator,"including"the"frontL runners,"delays"and"brokers."The"agents"in"previous"tests"were"largely" independent"of"other"agents,"and"would"rarely"interact"with"agents"other"than" the"exchange."" " With"these"experiments,"however,"the"frontLrunner"servers"would"send"data"to" each"other"and"the"delays"have"specific"destinations,"depending"on"what"agents" were"involved"in"the"experiment."This"created"an"added"complexity"to"the" simulations,"where"the"existing"infrastructure"for"setting"up"an"experiment" would"no"longer"be"suitable." "

7.1.3. Objective)3:)Modularise)the)Components,)Improving)the)Ease)of) Testing) " The"parameters"for"each"agent"have"been"moved"to"Agent.hs,"which"acts"as"a" centralised"control"panel"for"the"experiment"setup."Each"parameter"now"has" meaningful"identifiers"with"clear"and"simple"comments"that"explain"what"they" are"for."This"way,"the"tester"can"edit"the"lists"of"agents,"their"parameters"and"the" links"between"them"by"editing"Agent.hs."Once"the"experiment"structure"has"been" setup,"only"the"agent"lists"and"id"lists"need"editing"to"change"the"number"of" agents"involved,"as"detailed"in"the"user"manual,"in"Section"8.3." " "

56" 7.1.4. Objective)4:)Design)and)Simulate)Experiments) " Each"experiment"has"been"designed"to"outline"the"exact"causes"of"frontLrunner" losses,"and"they"have"all"achieved"in"doing"so."Further"to"completing"this" objective,"some"of"the"experiments"have"needed"more"than"one"simulation"with" the"same"parameters."This"is"not"only"due"to"debugging,"but"also"since"some" experiments"have"yielded"results"that"have"led"to"a"change"in"the"frontLrunning" algorithm,"attempting"to"reduce"frontLrunner"losses." " These"experiments"were"simulated"a"number"of"times,"using"different"sets"of" parameter"values"to"ensure"consistency."With"some"edge"cases"and"unlikely" parameters"the"results"have"been"unexpected,"but"the"trace"files"have"always" explained"the"reasons"behind"the"apparent"anomalies." "

7.1.5. Objective)5:)Analyse)the)Results) " Conclusions"have"been"drawn"from"the"results"in"every"case,"and"the" circumstances"in"which"a"frontLrunner"makes"a"profit"or"a"loss"have"been" defined."" " In"cases"where"the"results"have"revealed"that"the"frontLrunner’s"algorithm"can"be" improved"to"reduce"losses,"the"experiment"is"repeated"with"the"new"algorithm," and"the"results"have"been"compared." " 7.2. Conclusion) " The"assumptions"that"have"been"made"to"allow"the"frontLrunners"to"turn"a"profit" are"already"farfetched."Information"about"the"total"sizes"of"the"orders"to"be"sent" and"the"latency"between"each"broker"and"the"exchanges"would"be"very"difficult" to"ascertain."Even"still,"in"every"set"of"results"there"are"conditions"that"comprise" expected"profits,"and"so"in"any"case"the"results"disprove"the"original"null" hypothesis,"stating"that"profits"are"guaranteed"and"riskLfree." " The"first"experiment"showed"that,"to"profit"from"frontLrunning"at"all,"the"time" difference"between"one"part"of"a"broker’s"order"arriving"at"one"exchange"and" another"part"arriving"at"another"must"be"sufficient"enough"to"allow"the"frontL runners"to"frontLrun"the"order"during"that"time"interval." " From"the"second"experiment,"with"multiple"brokers,"it"is"clear"that"the"time"delay" between"different"broker’s"orders"getting"to"an"exchange"must"be"sufficient" enough"to"allow"the"updated"data"from"the"exchange"to"reach"the"frontLrunners"if" they"are"to"turn"a"profit."This"is"so"that"they"do"not"base"their"frontLrunning" calculations"on"historic"data."Otherwise,"they"will"miscalculate"the"prices"for" their"frontLrunning"orders,"which"could"incur"losses." " The"third"setup,"which"included"multiple"frontLrunners,"showed"that"the"first" frontLrunner"to"frontLrun"the"order"would"profit"from"it,"whether"the"broker’s"

57" incoming"market"order"matches"with"the"frontLrunner’s"offer"or"another"frontL runner’s"frontLrunning"market"order"does." " Other"variables"that"could"affect"these"results"include"cancellations,"limitLorder" expiration"and"varying"latency"dependant"on"different"paths"through"the" network"that"data"packets"take."They"have"not"been"considered"in"these" experiments,"but"such"factors"would"affect"delay"times"and"cause"pricing" interferences"in"much"the"same"way"as"the"tests"have"shown."" " 7.3. Further)Work) " It"is"clear"to"see"that"even"if"Michael"Lewis"is"given"the"benefit"of"the"doubt,"most" complexities"are"stripped"away"and"assumptions"are"made"to"favour"his"claims," at"the"very"least"his"insinuations"are"illLconceived."There"is"an"obvious"element"of" risk"associated"with"frontLrunning"in"this"way,"especially"when"considering"that" the"margin"for"error"would"be"a"minute"fraction"of"a"second"across"a"large" network." " Nevertheless,"this"project"serves"as"a"building"block"to"explore"the"intricacies"of" frontLrunning"algorithms"and"the"issues"involved."Many"research"papers"seem"to" discuss"highLfrequency"trading"and"frontLrunning"as"a"subject"of"controversy" concerning"market"volatility"and"legality,"although"fewer"seem"to"deal"with"the" specifics"of"its"implementation"and"risk"evaluation."Hopefully,"this"project"can" begin"to"categorise"frontLrunning"as"a"legitimate"highLfrequency"trading"strategy," rather"than"a"loophole"exploit"that"requires"regulatory"action." " To"advance"these"findings,"perhaps"the"focus"of"future"projects"could"be"to" develop,"compare"and"contrast"different"frontLrunning"algorithms"to"determine" which"would"mitigate"risk,"ameliorate"losses"and"be"most"lucrative."" Using"the"formulae"above,"even"with"fewer"assumptions,"the"broker’s"algorithms" could"be"improved"to"combat"against"this"kind"of"frontLrunning"by,"for"example," using"the"known"latencies"to"send"different"parts"of"the"orders"at"different"times." This"could"mean"that"different"parts"of"the"client’s"original"order"will"arrive"at" their"respective"exchanges"at"nearly"the"same"time,"which"would"allow"less"time" for"frontLrunners"to"frontLrun"them."This"is"yet"another"subject"area"of"study"that" could"be"considered." " In"terms"of"the"Haskell"simulator’s"infrastructure,"as"the"user"manual"in"Section" 8.3"indicates,"having"separate"delay"agents"complicates"the"process"of"setting"up" large"custom"experiments."Instead,"the"delays"could"be"integrated"as"part"of"the" other"agents,"or"handled"by"the"simulator"module"itself"depending"on"given" parameters."Since"the"simulator"allocates"the"agent"ids"and"there"would"be"no" delay"agents,"this"would"make"it"possible"to"reduce"the"number"of"steps"involved" in"creating"a"new"complicated"experiment"significantly." " "

58" 8. Appendix) 8.1. References) " [1]"Rob"Iati."(2009,"July)"The"Real"Story"Of"Trading"Espionage"Software."[Online]." http://www.wallstreetandtech.com/tradingLtechnology/theLrealLstoryLofL tradingLsoftwareLespionage/a/dLid/1262125?" [2]"Michael"Lewis,"Flash-Boys:-A-Wall-Street-Revolt.,"2014,"p."100." [3]"Micheal"Lewis,"Flash-Boys:-A-Wall-Street-Revolt.,"2014,"p."102." [4]"K"Alice"Ross,"Will"Fitzgibbon,"and"Nick"Mathiason."(2012,"September)"Britain" opposes"MEPs"seeking"ban"on"highLfrequency"trading."[Online]." http://www.theguardian.com/business/2012/sep/16/mepsLbanLhighL frequencyLtrading" [5]"Michael"Lewis,"Flash-Boys:-A-Wall-Street-Revolt.,"2014,"p."53." [6]"Martin"D"Gould"et"al.,""Limit"order"books,""Quantitative-Finance,"vol."13:11," no."1709L1742,"August"2013."[Online]." http://dx.doi.org/10.1080/14697688.2013.803148" [7]"Michael"Lewis,"Flash-Boys:-A-Wall-Street-Revolt.,"2014,"p."15."

"

59" 8.2. Relevant+Simulator+Code+

8.2.1. Frontrunner.hs+ # module Frontrunner where import Comm import Agent import Sim_orderlist import Debug.Trace import Order import Messages

--Frontrunner size = 100 -- order size

-- Information: ------

-- returns latest orderlist and tradedata as messages to be sent to the other frontrunner frotherlogic :: Int -> Orderlist -> (Double,Double) -> Int -> [Order] -> [Msg_t] frotherlogic myid myorderlist mytradedata exchtofrdelayid mytrades = [orderlistbcast] ++ x where orderlistbcast = broadcastmessage (myid, 0) (broadcast_orderlist myorderlist) tradedatabcast = broadcastmessage (myid, 0) (broadcast_tradedata mytradedata) x | (mytradedata /= (0.0, 0.0)) && (mytrades == []) = [tradedatabcast] -- check mytrades is empty to prevent | otherwise = [] -- front-running own orders, e.g. if -- fr1 has traded, don't trigger front-running -- by sending trade data from fr1's order to fr2

-- returns list of orders to be sent to local exchange frmylogic :: Int -> Int -> Int -> Int -> [Orderlist] -> [Orderlist] -> Time -> (Double, Double) -> Int -> Int -> [Order] frmylogic myid otherid myexchid otherexchid myorderlists otherorderlists ti othertradedata alpha beta = if ((length myorderlists) == alpha) && ((length otherorderlists) == beta) then trace "frmylogic" (f myorderlists otherorderlists 0 0) else [] where f myorderlists otherorderlists mxosize oxosize | (mxosize + oxosize) >= size = trace "comparing orders" (compareorders mxosize oxosize othertradedata myorderlists otherorderlists ti myid) | (isreallyemptyorderlist mynewol) && (isreallyemptyorderlist othernewol) = [] | (isreallyemptyorderlist mynewol) = f myorderlists newotherorderlists mxosize newoxosize | (isreallyemptyorderlist othernewol) = f newmyorderlists otherorderlists newmxosize oxosize | (ol_getbestprice mynewol) < (ol_getbestprice othernewol) = f newmyorderlists otherorderlists newmxosize oxosize | otherwise = f myorderlists newotherorderlists mxosize newoxosize where mynewol = last myorderlists othernewol = last otherorderlists (newmynewol, newmxosize) = f1 mynewol mxosize (newothernewol, newoxosize) = f1 othernewol oxosize newmyorderlists = (init myorderlists) ++ [newmynewol] newotherorderlists = (init otherorderlists) ++ [newothernewol] f1 ol s = (newol,newsize) where (o,newol) = if ((isreallyemptyorderlist ol) == False) then ol_poplowest ol else (emptyorder, ([],Bids)) newsize = s + (order_getsize o)

60#

-- compare expected orders with actual trade data compareorders :: Double -> Double -> (Double, Double) -> [Orderlist] -> [Orderlist] -> Time -> Int -> [Order] compareorders myxosize otherxosize othertradedata myorderlists otherorderlists ti myid = if (otherxosize < (othertradevol + degofaccuracy)) && (otherxosize > (othertradevol - degofaccuracy)) then frontrun myxosize myorderlists ti myid else trace ("WRONG VOLUME, DON'T FRONT-RUN: " ++ show otherxosize ++ " SHOULD BE: " ++ show othertradevol ++ " TIME: " ++ show ti ++ " " ++ show (last otherorderlists)) [] where degofaccuracy = 5 (othertradeprice, othertradevol) = othertradedata

-- returns orders for local exchange (frontrunning) frontrun :: Double -> [Orderlist] -> Time -> Int -> [Order] frontrun myxosize myorderlists ti myid = trace ((show myid) ++ " FRONTRUNNING") ([order_create 0.1 myxosize ti (HFT myid) (Buy Andkill), order_create sellprice myxosize ti (HFT myid) (Offer Goodtillcancelled)]) where latestmyorderlist = head myorderlists sellprice = findfrontrunprice latestmyorderlist myxosize

findfrontrunprice :: Orderlist -> Double -> Double findfrontrunprice latestmyorderlist mybuyordersize | lowestorder == emptyorder = 2020 -- if there are no offers left on the orderlist, sell for very high price | mybuyordersize > 0 = findfrontrunprice newlatestmyorderlist newmybuyordersize | otherwise = ((ol_getbestprice latestmyorderlist) - 1) where (lowestorder, newlatestmyorderlist) = if ((isreallyemptyorderlist latestmyorderlist) == False) then ol_poplowest latestmyorderlist else (emptyorder, ([],Asks)) newmybuyordersize = mybuyordersize - (order_getsize lowestorder)

frwrapper :: Agent_t frwrapper (Emptyagentstate) args any myid = (frwrapper (Fragstate (0, [0], [], [], [], [], getsent, (map (order_setuid "frwrapper") [0..]), (map fromIntegral(drop 15 rnds)), [])) args any myid) where rnds = drop myid randoms getsent| (arg_getstr (si "eerc:1" args 0)) == "Calm" = Calm | (arg_getstr (si "errc:2" args 0)) == "Choppy" = Choppy | (arg_getstr (si "errc:3" args 0)) == "Ramp" = Ramp | (arg_getstr (si "errc:4" args 0)) == "Toxic" = Toxic | otherwise = error "Unrecognised sentiment." frwrapper (Fragstate (profit, [invent], oldmyorderlists_broker1, oldotherorderlists_broker1, oldmyorderlists_broker2, oldotherorderlists_broker2, sent, uids, rnds, any)) args ((ti, messages, broadcasts) : simstateinfos) myid = if (myorders /= []) then trace ("FR" ++ (show myid) ++ " profit: " ++ (show newprofit)) ((myexchorders ++ dataforotherexch) : (frwrapper (Fragstate (newprofit, [newinvent], myorderlists_broker1, otherorderlists_broker1, myorderlists_broker2, otherorderlists_broker2, sent, remaininguids, (drop 15 rnds), any)) args simstateinfos myid)) else trace ("FR" ++ (show myid) ++ " profit: " ++ (show newprofit)) ((dataforotherexch : frwrapper (Fragstate (newprofit, [newinvent], myorderlists_broker1, otherorderlists_broker1, myorderlists_broker2, otherorderlists_broker2, sent, remaininguids, (drop 15 rnds), any)) args simstateinfos myid)) where myexchorders = map (ordermessage (myid, frtoexchdelayid)) (fmyorders) (remaininguids, fmyorders) = applyuids uids myorders mytrades = map (cpsafehd "frwrapper1") (filter (not.null) (map msg_gettrade messages)) newinvent = foldr (+) invent (map getmovement mytrades) where getmovement o |(isBuySide o) = (order_getsize o) |(isSellSide o) = (- (order_getsize o)) |otherwise = error "frwrapper - getmovement - order type not recognised." newprofit = foldr (+) profit (map getprofit mytrades) where getprofit o |(isSellSide o) = trace ("time-step: " ++ (show ti) ++ " sell: " ++ (show o)) ((order_getsize o)*(order_getprice o)) |(isBuySide o) = trace ("time-step: " ++ (show ti) ++ " buy: " ++ (show o)) (- ((order_getsize o)*(order_getprice o))) |otherwise = error "frwrapper - getprice - order type not recognised."

myorders | (othertradedata /= (0.0,0.0)) && ((max broker1alpha broker2alpha) == broker1alpha) = if ((frmylogic myid otherid myexchid otherexchid myorderlists_broker1 otherorderlists_broker1 ti othertradedata broker1alpha broker1beta)) /= [] then ((frmylogic myid otherid myexchid otherexchid myorderlists_broker1 otherorderlists_broker1 ti othertradedata broker1alpha broker1beta))

61# else ((frmylogic myid otherid myexchid otherexchid myorderlists_broker2 otherorderlists_broker2 ti othertradedata broker2alpha broker2beta)) | (othertradedata /= (0.0,0.0)) && ((max broker1alpha broker2alpha) == broker2alpha) = if ((frmylogic myid otherid myexchid otherexchid myorderlists_broker2 otherorderlists_broker2 ti othertradedata broker2alpha broker2beta)) /= [] then ((frmylogic myid otherid myexchid otherexchid myorderlists_broker2 otherorderlists_broker2 ti othertradedata broker2alpha broker2beta)) else ((frmylogic myid otherid myexchid otherexchid myorderlists_broker1 otherorderlists_broker1 ti othertradedata broker1alpha broker1beta)) | otherwise = []

dataforotherexch = frotherlogic myid myneworderlist mytradedata exchtofrdelayid mytrades

myneworderlist = if (msg_isbroadcast mynewol_bcast) then broadcast_getorderlist (msg_getbroadcast mynewol_bcast) else ([],Asks) otherneworderlist = if (msg_isbroadcast othernewol_bcast) then broadcast_getorderlist (msg_getbroadcast othernewol_bcast) else ([],Asks)

mynewol_bcast = (findolbcast broadcasts exchtofrdelayid ti) othernewol_bcast = (findolbcast broadcasts otherfrdelayid ti)

myorderlists_broker1 = (myorderlists_insert myneworderlist oldmyorderlists_broker1 broker1alpha) otherorderlists_broker1 = (otherorderlists_insert otherneworderlist oldotherorderlists_broker1 broker1beta)

myorderlists_broker2 = (myorderlists_insert myneworderlist oldmyorderlists_broker2 broker2alpha) otherorderlists_broker2 = (otherorderlists_insert otherneworderlist oldotherorderlists_broker2 broker2beta)

mytradedata = if (mynewtd_bcasts /= []) then (accumulatetradedatavolume (map broadcast_gettradedata (map msg_getbroadcast mynewtd_bcasts))) else (0.0, 0.0) othertradedata = if (othernewtd_bcasts /= []) then (accumulatetradedatavolume (map broadcast_gettradedata (map msg_getbroadcast othernewtd_bcasts))) else (0.0, 0.0)

mynewtd_bcasts = (findtdbcasts broadcasts exchtofrdelayid ti) othernewtd_bcasts = (findtdbcasts broadcasts otherfrdelayid ti)

broker1alpha | myid == fr1id = ((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch2tofr2delay + 2) + (fr2tofr1delay + 2) - (exch1tofr1delay + 2) | myid == fr2id = ((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch1tofr1delay + 2) + (fr1tofr2delay + 2) - (exch2tofr2delay + 2) | myid == fr3id = ((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch2tofr4delay + 2) + (fr4tofr3delay + 2) - (exch1tofr3delay + 2) | myid == fr4id = ((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch1tofr3delay + 2) + (fr3tofr4delay + 2) - (exch2tofr4delay + 2) | otherwise = error "alpha: couldn't find broker id" broker2alpha | myid == fr1id = ((max exch1tobroker2delay exch2tobroker2delay) + 2) + ((min broker2toexch1delay broker2toexch2delay) + 2) + (exch2tofr2delay + 2) + (fr2tofr1delay + 2) - (exch1tofr1delay + 2) | myid == fr2id = ((max exch1tobroker2delay exch2tobroker2delay) + 2) + ((min broker2toexch1delay broker2toexch2delay) + 2) + (exch1tofr1delay + 2) + (fr1tofr2delay + 2) - (exch2tofr2delay + 2) | myid == fr3id = ((max exch1tobroker2delay exch2tobroker2delay) + 2) + ((min broker2toexch1delay broker2toexch2delay) + 2) + (exch2tofr4delay + 2) + (fr4tofr3delay + 2) - (exch1tofr3delay + 2) | myid == fr4id = ((max exch1tobroker2delay exch2tobroker2delay) + 2) + ((min broker2toexch1delay broker2toexch2delay) + 2) + (exch1tofr3delay + 2) + (fr3tofr4delay + 2) - (exch2tofr4delay + 2) | otherwise = error "alpha: couldn't find broker id"

broker1beta = ((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) -- simplified beta broker2beta = ((max exch1tobroker2delay exch2tobroker2delay) + 2) + ((min broker2toexch1delay broker2toexch2delay) + 2) -- simplified beta

-- fullbeta | myid == fr1id = (((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch2tofr2delay + 2) + (fr2tofr1delay + 2) - (exch2tofr2delay + 2) - (fr2tofr1delay + 2)) -- | myid == fr2id = (((max exch1tobroker1delay exch2tobroker1delay) + 2) + ((min broker1toexch1delay broker1toexch2delay) + 2) + (exch1tofr1delay + 2) + (fr1tofr2delay + 2) - (exch1tofr1delay + 2) - (fr1tofr2delay + 2))

-- the ids of the two delay agents that send data as broadcasts (otherfrdelayid,exchtofrdelayid) = fr_getmydelayids myid

frtoexchdelayid = fr_getexchdelayid myid

(otherid, myexchid, otherexchid) = fr_findids myid

accumulatetradedatavolume :: [(Double,Double)] -> (Double,Double) accumulatetradedatavolume [] = error "accumulatetradedatavolume: empty list of trade data" accumulatetradedatavolume ((p,v1):[]) = (p,v1) accumulatetradedatavolume ((p,v1):(p2,v2):[]) = (p,v1+v2) accumulatetradedatavolume ((p,v1):(p2,v2):xs) = accumulatetradedatavolume ((p,v1+v2):xs)

findtdbcasts :: [Msg_t] -> Int -> Time -> [Msg_t] findtdbcasts [] fromid ti = []

62# findtdbcasts (f:r) fromid ti = if (msg_isbroadcast f) && (broadcast_is_tradedata (msg_getbroadcast f)) && ((msg_getfromid f) == fromid) then (f : findtdbcasts r fromid ti) else findtdbcasts r fromid ti findolbcast :: [Msg_t] -> Int -> Time -> Msg_t findolbcast [] fromid ti = Hiaton findolbcast (f:r) fromid ti = if (msg_isbroadcast f) && (broadcast_is_orderlist (msg_getbroadcast f)) && (ol_gettype (broadcast_getorderlist (msg_getbroadcast f)) == Asks) && ((msg_getfromid f) == fromid) then f else findolbcast r fromid ti

--Helpers ------myorderlists_insert ol ollist alpha = if (length ollist) == alpha then ol : (init ollist) else ol : ollist otherorderlists_insert ol ollist beta = if (length ollist) == beta then ol : (init ollist) else ol : ollist

8.2.2. Broker.hs+ # module Broker where import Comm import Agent import Sim_orderlist import Debug.Trace import Sim_orderlist

--Broker size = 100 -- order size

-- Information: ------

-- returns orders to be sent to each exchange brokerlogic :: Double -> Int -> Int -> Int -> Orderlist -> Orderlist -> Time -> (Order, Order) brokerlogic inventory myid myexchid otherexchid mynewol othernewol ti = f mynewol othernewol 0 0 where f mynewol othernewol mxosize oxosize | (mxosize + oxosize) >= size = (myorder,otherorder) | (isreallyemptyorderlist mynewol) && (isreallyemptyorderlist othernewol) = (emptyorder, emptyorder) | (isreallyemptyorderlist mynewol) = (f mynewol newothernewol mxosize newoxosize) | (isreallyemptyorderlist othernewol) = (f newmynewol othernewol newmxosize oxosize) | (ol_getbestprice mynewol) < (ol_getbestprice othernewol) = (f newmynewol othernewol newmxosize oxosize) | otherwise = (f mynewol newothernewol mxosize newoxosize) where myorder = order_create 0.1 mxosize ti (HFT myid) (Buy Andkill) otherorder = order_create 0.1 oxosize ti (HFT myid) (Buy Andkill) (newmynewol, newmxosize) = f1 mynewol mxosize (newothernewol, newoxosize) = f1 othernewol oxosize f1 ol s = (newol,newsize) where (o,newol) = ol_poplowest ol newsize = (s + (order_getsize o))

63#

brokerwrapper :: Agent_t brokerwrapper (Emptyagentstate) args any myid = brokerwrapper (Brokeragstate (False, [0], getsent, (map (order_setuid "brokerwrapper") [0..]), (map fromIntegral(drop 15 rnds)), [])) args any myid where rnds = drop myid randoms getsent| (arg_getstr (si "eerc:1" args 0)) == "Calm" = Calm | (arg_getstr (si "errc:2" args 0)) == "Choppy" = Choppy | (arg_getstr (si "errc:3" args 0)) == "Ramp" = Ramp | (arg_getstr (si "errc:4" args 0)) == "Toxic" = Toxic | otherwise = error "Unrecognised sentiment." brokerwrapper (Brokeragstate (ordersplaced, [invent], sent, uids, rnds, any)) args ((ti, messages, broadcasts) : simstateinfos) myid = if (myol_bcast /= Hiaton) && (otherol_bcast /= Hiaton) && ((isreallyemptyorderlist myneworderlist) == False) && ((isreallyemptyorderlist otherneworderlist) == False) && ((isemptyorder myexchorder) == False) && ((isemptyorder otherexchorder) == False) && ordersplaced == False then (([myexchmsg] ++ [otherexchmsg]) : (brokerwrapper (Brokeragstate (True, [newinvent], sent, remaininguids2, (drop 15 rnds), any)) args simstateinfos myid)) else (([Hiaton] : brokerwrapper (Brokeragstate (ordersplaced, [newinvent], sent, remaininguids2, (drop 15 rnds), any)) args simstateinfos myid)) where myexchmsg = ordermessage (myid, brokertomyexchdelayid) (head fmyorders) otherexchmsg = ordermessage (myid, brokertootherexchdelayid) (head fotherorders) (remaininguids1, fmyorders) = applyuids uids [myexchorder] (remaininguids2, fotherorders) = applyuids remaininguids1 [otherexchorder] mytrades = map (cpsafehd "brokerwrapper") (filter (not.null) (map msg_gettrade messages)) newinvent = foldr (+) invent (map getmovement mytrades) where getmovement o |(isBuySide o) = (order_getsize o) |(isSellSide o) = (- (order_getsize o)) |otherwise = error "brokerwrapper - getmovement - order type not recognised." (myexchorder, otherexchorder) = if ((isreallyemptyorderlist myneworderlist) == False) && ((isreallyemptyorderlist otherneworderlist) == False) then brokerlogic invent myid myexchid otherexchid myneworderlist otherneworderlist ti else (emptyorder, emptyorder)

myneworderlist = if (msg_isbroadcast myol_bcast) then broadcast_getorderlist (msg_getbroadcast myol_bcast) else ([],Asks) otherneworderlist = if (msg_isbroadcast otherol_bcast) then broadcast_getorderlist (msg_getbroadcast otherol_bcast) else ([],Asks)

myol_bcast = (findmyolbcast broadcasts myexchtobrokerdelayid ti) otherol_bcast = (findotherolbcast broadcasts otherexchtobrokerid ti)

(myexchtobrokerdelayid, otherexchtobrokerid) = broker_getmydelayids myid (brokertomyexchdelayid, brokertootherexchdelayid) = broker_getexchdelayids myid

(myexchid, otherexchid) = (fr1exchid, fr2exchid)

findmyolbcast :: [Msg_t] -> Int -> Time -> Msg_t findmyolbcast [] fromid ti = Hiaton findmyolbcast (f:r) fromid ti = if (msg_isbroadcast f) && ((msg_getfromid f) == fromid) && (broadcast_is_orderlist (msg_getbroadcast f)) && (ol_gettype (broadcast_getorderlist (msg_getbroadcast f)) == Asks) then f else findmyolbcast r fromid ti findotherolbcast :: [Msg_t] -> Int -> Time -> Msg_t findotherolbcast [] fromid ti = Hiaton findotherolbcast (f:r) fromid ti = if (msg_isbroadcast f) && ((msg_getfromid f) == fromid) && (broadcast_is_orderlist (msg_getbroadcast f)) && (ol_gettype (broadcast_getorderlist (msg_getbroadcast f)) == Asks) then f else findotherolbcast r fromid ti

#

64# 8.2.3. Agent.hs+Snippet+ # fr2tofr1delayid = 1 fr1tofr2delayid = 2 exch1tofr1delayid = 3 exch2tofr2delayid = 4 broker1toexch1delayid = 5 broker1toexch2delayid = 6 exch1tobroker1delayid = 7 exch2tobroker1delayid = 8 fr1toexch1delayid = 9 fr2toexch2delayid = 10 broker2toexch1delayid = 11 broker2toexch2delayid = 12 exch1tobroker2delayid = 13 exch2tobroker2delayid = 14 fr4tofr3delayid = 15 fr3tofr4delayid = 16 exch1tofr3delayid = 17 exch2tofr4delayid = 18 fr3toexch1delayid = 19 fr4toexch2delayid = 20 fr1exchid = 21 -- exch1 id fr2exchid = 22 -- exch2 id fr1id = 23 fr2id = 24 fr3id = 25 fr4id = 26 broker1id = 27 broker2id = 28

-- Delay amounts fr2tofr1delay = 1 -- from fr2 to fr1 fr1tofr2delay = 1 -- from fr1 to fr2 exch1tofr1delay = 1 exch2tofr2delay = 9 broker1toexch1delay = 1 broker1toexch2delay = broker1toexch1delay + 9 + (max (exch1tofr1delay + fr1tofr2delay + fr2toexch2delay) (exch1tofr3delay + fr3tofr4delay + fr4toexch2delay)) exch1tobroker1delay = broker1toexch1delay exch2tobroker1delay = broker1toexch2delay fr1toexch1delay = exch1tofr1delay fr2toexch2delay = exch2tofr2delay broker2toexch1delay = broker2toexch2delay + 9 + (max (exch1tofr1delay + fr1tofr2delay + fr2toexch2delay) (exch1tofr3delay + fr3tofr4delay + fr4toexch2delay)) broker2toexch2delay = 1 exch1tobroker2delay = broker2toexch1delay exch2tobroker2delay = broker2toexch2delay fr4tofr3delay = 1 fr3tofr4delay = 1 exch1tofr3delay = 9 exch2tofr4delay = fr2toexch2delay fr3toexch1delay = exch1tofr3delay fr4toexch2delay = 1

-- Agent lists broadcast_channels = (length delay_list) + (length exchange_list) + (length broker_list) + (length frontrunner_list) exchange_list = [fr1exchid,fr2exchid] broker_list = [broker1id] frontrunner_list = [fr1id,fr2id,fr3id,fr4id]

-- Delay Lookup lists (mapping from delay id to element in lists)

65#

-- delayid delay_list = [fr2tofr1delay, -- 1 fr1tofr2delay, -- 2 exch1tofr1delay, -- 3 exch2tofr2delay, -- 4 broker1toexch1delay, -- 5 broker1toexch2delay, -- 6 exch1tobroker1delay, -- 7 exch2tobroker1delay, -- 8 fr1toexch1delay, -- 9 fr2toexch2delay, -- 10 broker2toexch1delay, -- 11 broker2toexch2delay, -- 12 exch1tobroker2delay, -- 13 exch2tobroker2delay, -- 14 fr4tofr3delay, -- 15 fr3tofr4delay, -- 16 exch1tofr3delay, -- 17 exch2tofr4delay, -- 18 fr3toexch1delay, -- 19 fr4toexch2delay] -- 20 delay_init_list = [(fr2id,fr1id), (fr1id,fr2id), (fr1exchid,fr1id), (fr2exchid,fr2id), (broker1id,fr1exchid), -- (sender,destination) (broker1id,fr2exchid), (fr1exchid,broker1id), (fr2exchid,broker1id), (fr1id,fr1exchid), (fr2id,fr2exchid), (broker2id,fr1exchid), (broker2id,fr2exchid), (fr1exchid,broker2id), (fr2exchid,broker2id), (fr4id,fr3id), (fr3id,fr4id), (fr1exchid,fr3id), (fr2exchid,fr4id), (fr3id,fr1exchid), (fr4id,fr2exchid)]

------Helper functions (for frontrunning) ------

-- returns (otherfrid, myexchid, otherexchangeid) fr_findids :: Int -> (Int,Int,Int) fr_findids frid | frid == fr1id = (fr2id, fr1exchid, fr2exchid) | frid == fr2id = (fr1id, fr2exchid, fr1exchid) | frid == fr3id = (fr4id, fr1exchid, fr2exchid) | frid == fr4id = (fr3id, fr2exchid, fr1exchid) | otherwise = error ("findotherexch: Not valid id to find other exchange")

-- delay from other front runner to this front runner, and delay from local exchange -- to this front runner, to receive both exchange's trade data and orderlists fr_getmydelayids frid | frid == fr1id = (fr2tofr1delayid,exch1tofr1delayid) | frid == fr2id = (fr1tofr2delayid,exch2tofr2delayid) | frid == fr3id = (fr4tofr3delayid,exch1tofr3delayid) | frid == fr4id = (fr3tofr4delayid,exch2tofr4delayid) | otherwise = error ("fr_getmydelayids: Not valid frid")

-- delay from frontrunner to local exchange

66# fr_getexchdelayid frid | frid == fr1id = fr1toexch1delayid | frid == fr2id = fr2toexch2delayid | frid == fr3id = fr3toexch1delayid | frid == fr4id = fr4toexch2delayid | otherwise = error ("fr_getexchdelayid: Not a valid frid")

-- delay from exchanges to this broker broker_getmydelayids brokerid | brokerid == broker1id = (exch1tobroker1delayid,exch2tobroker1delayid) | brokerid == broker2id = (exch1tobroker2delayid,exch2tobroker2delayid) | otherwise = error "broker_getmydelayids: brokerid not recognised"

-- delay from broker to each exchange broker_getexchdelayids brokerid | brokerid == broker1id = (broker1toexch1delayid,broker1toexch2delayid) | brokerid == broker2id = (broker2toexch1delayid,broker2toexch2delayid) | otherwise = error "broker_getexchdelayids: brokerid not recognised"

-- for the exchange to send trade messages via delays, instead of the traders directly exch_getdelaysfromtraderids exchid traderid | (traderid == fr1id) && (exchid == fr1exchid) = exch1tofr1delayid | (traderid == fr2id) && (exchid == fr2exchid) = exch2tofr2delayid | (traderid == fr3id) && (exchid == fr1exchid) = exch1tofr3delayid | (traderid == fr4id) && (exchid == fr2exchid) = exch2tofr4delayid | otherwise = traderid

#

8.2.4. Messages.hs+ # module Messages where import Order import Comm import Sim_orderlist

--The message type & broadcast message type ------

--Key here in broadcast message is group id. Msg is targetid followed by (key,value) pairs (and underlying object?) instance C_msg_t Msg_t where hiaton = Hiaton

--constructors. message x args = Message x args debugmessage x y = Debugmessage x y ordermessage x anOrder = Ordermessage x anOrder broadcastmessage x broadcast = Broadcastmessage x broadcast cancelmessage fromto idtuple = Cancelmessage fromto idtuple trademessage fromto ordera orderb = Trademessage fromto ordera orderb datamessage from dat = Datamessage from dat ackmessage fromto ackd x msgg = (Ackmessage fromto ackd x msgg)

--msg_t functions msg_getid Hiaton = 0 msg_getid (Message (from,to) args) = to msg_getid (Ordermessage (from,to) args) = to msg_getid (Broadcastmessage (from,to) args) = to msg_getid (Trademessage (from,to) ordera orderb) = to msg_getid (Datamessage (from, to) dat) = to

67# msg_getid (Ackmessage (d,e) b c m) = e msg_getid (Cancelmessage (f,t) b) = t msg_getid (Debugmessage (f,t) m) = t msg_getfromid Hiaton = 0 msg_getfromid (Message (from,to) args) = from msg_getfromid (Ordermessage (from,to) args) = from msg_getfromid (Broadcastmessage (from,to) args) = from msg_getfromid (Trademessage (from,to) ordera orderb) = from msg_getfromid (Datamessage (from, to) dat) = from msg_getfromid (Ackmessage (d,e) b c m) = d msg_getfromid (Cancelmessage (f,t) b) = f msg_getfromid (Debugmessage (f,t) m) = f msg_setids newfrom newto Hiaton = Hiaton msg_setids newfrom newto (Message (from,to) args) = (Message (newfrom,newto) args) msg_setids newfrom newto (Ordermessage (from,to) args) = (Ordermessage (newfrom,newto) args) msg_setids newfrom newto (Broadcastmessage (from,to) args) = (Broadcastmessage (newfrom,newto) args) msg_setids newfrom newto (Trademessage (from,to) ordera orderb) = (Trademessage (newfrom,newto) ordera orderb) msg_setids newfrom newto (Datamessage (from, to) dat) = (Datamessage (newfrom, newto) dat) msg_setids newfrom newto (Ackmessage (from, to) b c m) = (Ackmessage (newfrom, newto) b c m) msg_setids newfrom newto (Cancelmessage (from, to) b) = (Cancelmessage (newfrom, newto) b) msg_setids newfrom newto (Debugmessage (from, to) m) = (Debugmessage (newfrom, newto) m) msgbcast_setfromid newfrom (Broadcastmessage (from,to) args) = (Broadcastmessage (newfrom,to) args) showmsg_t Hiaton = "\nHiaton" showmsg_t (Datamessage x dat) = "Data message" showmsg_t (Cancelmessage x (trader, order)) = "\nMessage from/to " ++ (show x) ++ ": Trader #" ++ (show trader) ++ " is cancelling order " ++ (show order) showmsg_t (Message x args) = "\nMessage from/to "++(show x)++" ["++(concat (map arg_getstr args)) ++ "]\n" showmsg_t (Ordermessage x args) = "\nMessage from/to "++(show x)++" "++(showorder args) ++ "" showmsg_t (Broadcastmessage x args) = "\nBroadcast from/to group "++(show x)++" ["++(showbroadcast_t args) ++ "]" showmsg_t (Trademessage (from,to) ordera orderb) = "\n======\n\nTo: " ++ (show to) ++ "\nOrder: \n" ++ (show ordera) ++ "\n\n matched with\n\nOrder:" ++ (show orderb) ++ "\n\n======" showmsg_t (Ackmessage (d,e) b c m) = "\nAckmessage(" ++ (show d) ++ "->" ++ (show e) ++ "): The following order " ++ text ++ (show c) where text| b /= 0 = "was unsuccessful because " ++ m ++ ": \n" | b == 5 = "was cancelled successfully." | otherwise = "was successful: \n" showmsg_t (Debugmessage ft m) = "\n+=+=+=+=+=+=+=+=+=+=+=+=+=\nDebug message:" ++ (show ft) ++ "\n" ++ m ++ "\n+=+=+=+=+=+=+=+=+=+=+=+=+=" msg_disptrace (Datamessage x dat) = dat msg_disptrace any = ""

msg_getnumlistfrombcast (Broadcastmessage a b) = broadcast_getnumlist b msg_isbroadcast (Broadcastmessage a b) = True msg_isbroadcast any = False msg_isorder (Ordermessage a b) = True msg_isorder any = False msg_isdata (Datamessage a b) = True msg_isdata any = False msg_isack (Ackmessage a b c m) = True msg_isack any = False msg_getackcode (Ackmessage a b c m) = b msg_getackcode any = error "msg_getackcode - calling get ack code on non-ack message." msg_getackdorder (Ackmessage a b c m) = c msg_getackdorder any = error "msg-getackdorder - Called this on a non-ack message" msg_getackdorderaslist (Ackmessage a b c m) = [c] msg_getackdorderaslist any = error "msg-getackdorder - Called this on a non-ack message" msg_istrade (Trademessage (from,to) ordera orderb) = True msg_istrade any = False msg_isreject (Ackmessage a b c m) = b /= 0 msg_isreject any = error "msg_isreject called on non-ack message." msg_getbroadcast (Broadcastmessage a b) = b msg_getbroadcast any = error "Make sure you're trying to get the broadcast FROM a broadcast message first..." msg_getorders [] = [] msg_getorders ((Ordermessage a b) : rest) = b : (msg_getorders rest) msg_getorders (any:rest) = msg_getorders rest msg_gettrade (Trademessage (from,to) ordera orderb) = [ordera, orderb] msg_gettrade any = [] msg_gettradeFrom (Trademessage (from,to) ordera orderb) = [from] msg_gettradeFrom any = [] msg_gettradeTo (Trademessage (from,to) ordera orderb) = [to] msg_gettradeTo any = [] msg_getcanceltuple (Cancelmessage x b) = [b]

68# msg_getcanceltuple any = [] msg_getgoodack (Ackmessage (d,e) b c m) = if (b == 0) then [(d, e, c)] -- exchange, traderID, order else [] msg_getgoodack any = []

--map msg_getbroadcast

--The implementation of broadcasts

instance C_broadcast_t Broadcast_t where showbroadcast_t (Numlistbroadcast nums) = "LOBbcast contents: [" ++ (show nums) ++ "]" showbroadcast_t (Strbroadcast string) = show string showbroadcast_t (Orderlistbroadcast orderlist) = show orderlist showbroadcast_t (Tradebroadcast (price,vol)) = "TRADE DATA: " ++ (show (price,vol)) ++ " END OF TRADE" broadcast_getnumlist (Numlistbroadcast lobsum) = lobsum broadcast_getnumlist any = error "can't get numlist from non-numlist broadcast" broadcast_getorderlist (Orderlistbroadcast orderlist) = orderlist -- AGC 2015 (orderlist and trade data) broadcast_gettradedata (Tradebroadcast (price, vol)) = (price, vol) broadcast_gettradedata (Numlistbroadcast any) = error "ERROR" broadcast_gettradedata (Strbroadcast any) = error "ERROR" broadcast_gettradedata (Orderlistbroadcast any) = error "ERROR" broadcast_orderlist orderlist = Orderlistbroadcast orderlist broadcast_numlist ob = Numlistbroadcast ob broadcast_tradedata (price, vol) = Tradebroadcast (price, vol) broadcast_str string = Strbroadcast string broadcast_is_numlist (Numlistbroadcast x) = True broadcast_is_numlist any = False broadcast_is_str (Strbroadcast x) = True broadcast_is_str any = False broadcast_is_orderlist (Orderlistbroadcast x) = True broadcast_is_orderlist any = False broadcast_is_tradedata (Tradebroadcast x) = True broadcast_is_tradedata any = False

#

8.2.5. TestHarness.hs+Snippet+ #

testfrontrunning :: IO () testfrontrunning = do createDirectoryIfMissing True ("tracefiles/"++thefilename) sim 100 meinargs meinagents where meinargs = [(Arg (Str "Calm", 1)), (Arg (Str "Randomise", 1)), (Arg (Str fthefilename, 9989793425))] fthefilename = "tracefiles/" ++ thefilename ++ "/" ++ thefilename thefilename = "Frontrunning" meinagents = delays ++ exchanges ++ frontrunners ++ brokers ++ traders delays = (rep (length delay_list) (delaywrapper, [0..broadcast_channels])) exchanges = (rep (length exchange_list) (nice_mime_wrapper, [0..broadcast_channels])) traders = [(mytraderwrapper, [0..broadcast_channels])] brokers = (rep (length broker_list) (brokerwrapper, [0..broadcast_channels])) frontrunners = (rep (length frontrunner_list) (frwrapper, [0..broadcast_channels]))

69# 8.2.6. Comm.hs+Snippets+ # --BASIC TYPES type Price = Double type Size = Double --really clumsy. It should be Int, but there are a lot of computations with Doubles. type Time = Int type Inventory = Size

data Ordertype = Bid Limitorder_t | Offer Limitorder_t | Sell Marketorder_t | Buy Marketorder_t | None | Abort deriving (Show,Eq) data Marketorder_t = Orkill | Andkill deriving (Show,Eq) data Limitorder_t = Goodtillcancelled | Goodtilldate Time -- Not sure where these two should be - Minimumquantity | Maximumquantity | Day deriving (Show,Eq) data Traderid = Phantom | Intermediary Int | HFT Int | FundSeller Int | FundBuyer Int | Small Int | Opportunistic Int | SSTaker Int | BSTaker Int | BSMaker Int | SSMaker Int | Maker Int | Taker Int deriving (Show,Eq) data Sentiment = Calm | Choppy | Ramp | Toxic deriving (Show,Eq) --need to test Eq type Order = (Price, Size, (Time, Time), Traderid, Ordertype, Int) data Orderlist_t = Bids | Asks deriving (Show,Eq) type Orderlist = ([(Price, [Order])], Orderlist_t) data Lob = LOB Bids Offers Buys_waiting Sells_waiting Trades_done Time Orders_received Sentiment Traderinfo Statstype deriving (Eq) type Lobsummary_t = [Double] type Lobtrace = [[Char]] type Bids = Orderlist type Offers = Orderlist type Buys_waiting = [Order] type Sells_waiting = [Order] type Trades_done = [(Order, Order)] type Orders_received = [Order] type Traderinfo = [Traderinfo_item] type Traderinfo_item = (Traderid, Percent_liquidity_taken, Penalty_applied, Time) -- time is time penalty was applied type Percent_liquidity_taken = Double type Penalty_applied = Time type Statstype = (Price,Price,Double,Double,Double,Double, -- underlying value, last traded price, squared error, cumulative squared error,samples,percent, (Size,Size,Size,Size), -- minliquiditybs, maxliquiditybs, liquiditybs, maxdrawdownbs, (Size,Size,Size,Size), -- minliquidityss, maxliquidityss, liquidityss, maxdrawdownss (Size,Size,Size,Size), -- minliquiditybstop, maxliquiditybstop, liquiditybstop, maxdrawdownbstop, (Size,Size,Size,Size), -- minliquiditysstop, maxliquiditysstop, liquiditysstop, maxdrawdownsstop (Size,Size,Size,Size), -- zeroliquiditybs, maxzeroliquiditybs, zeroliquidityss, maxzeroliquidityss (Size,Size,Size,Size) -- zeroliquiditybstop, maxzeroliquiditybstop, zeroliquiditysstop, maxzeroliquiditysstop )

data Msg_t = Hiaton | Cancelmessage (Int,Int) (Int,Int) | Message (Int,Int) [Arg_t] | Ordermessage (Int,Int) Order | Trademessage (Int,Int) Order Order| Broadcastmessage (Int,Int) Broadcast_t | Datamessage (Int,Int) [Char] | Ackmessage (Int,Int) Int Order [Char] | Debugmessage (Int,Int) [Char] deriving (Show,Eq) --(from,to) identifiers

data Broadcast_t = Numlistbroadcast [Double] | Strbroadcast Str | Orderlistbroadcast Orderlist | Tradebroadcast (Double, Double) deriving (Show,Eq) -- Add your self-defined broadcasts here

------#

type Agent_t = Agentstate_t -> [Arg_t] -> [(Int, [Msg_t], [Msg_t])] -> Int -> [[Msg_t]] --Agents take a tuple of (time, messages, broadcasts) last num is id from sim

70# data Agentstate_t = Agentstate (Double, Double, Int, Lob) | Emptyagentstate | Exchstate Lob | Nicemimestate Nice_mime_lob | Traderstate (Price, Price, Double, Sentiment, Double, [Order -> Order]) | Newagstate ([Double], [Order], Sentiment, [Order -> Order], [Double], [Double]) --traderstate is old_bestbid, old_bestoffer, old_ordernum | Fragstate (Double, [Double], [Orderlist], [Orderlist], [Orderlist], [Orderlist], Sentiment, [Order -> Order], [Double], [Double]) --traderstate is old_bestbid, old_bestoffer, old_ordernum | Brokeragstate (Bool, [Double], Sentiment, [Order -> Order], [Double], [Double]) | Mytraderagstate ([Double], Sentiment, [Order -> Order], [Double], [Double]) | Delaystate ([[Msg_t]], [[Msg_t]], Int, Int) deriving (Eq) emptyagentstate = Emptyagentstate -- we don't yet know what this will or should be instance Eq (Order -> Order) where x == y = True x /= y = not (x == y) data Nice_mime_lob = Nice_mime_lob Sentiment Listoftotals Nubids Nuoffers Time Ticksize Lasttradedprice Stats deriving (Eq) -- need to be confirmed type Listoftotals = [Double] type Stats = [Double] type Nubids = Orderlist type Nuoffers = Orderlist type Ticksize = Double type Tick = (Double, [Order]) type Lasttradedprice = Double

------#

8.2.7. Delay.hs+ # module Delay where import Comm import Agent import Messages import Debug.Trace

-- Logic of delay function: delay :: [Msg_t] -> Int -> [Msg_t] delay input delayhiatons = delay1 input (rep delayhiatons hiaton) delay1 :: [Msg_t] -> [Msg_t] -> [Msg_t] delay1 [] [] = [] delay1 [] (y:ys) = y : (delay1 [] (ys ++ [hiaton])) delay1 (x:xs) (y:ys) = y : (delay1 xs (ys ++ [x]))

-- Actual delay function: delaywrapper :: Agent_t delaywrapper (Emptyagentstate) args any myid = delaywrapper (Delaystate (delayinput, delaybuffer, sourceid, destinationid)) args any myid where delayinput = [] delaybuffer = rep delayamount [hiaton] delayamount = delay_list!!(myid-1) -- ids start from 1, id 0 is the sim itself (sourceid, destinationid) = delay_init_list!!(myid-1)

delaywrapper (Delaystate (delayinput, delaybuffer, sourceid, destinationid)) args ((ti, messages, broadcasts) : simstateinfos) myid = (delayedmsgs : (delaywrapper (Delaystate (newdelayinput, newdelaybuffer, sourceid, destinationid)) args simstateinfos myid)) where newdelaybuffer = if msgqueue /= [] then ((tail delaybuffer) ++ [head msgqueue]) else (tail delaybuffer) ++ [[hiaton]]

71# newdelayinput = if msgqueue /= [] then tail msgqueue else [] delayedmsgs = head delaybuffer msgqueue = if (mybcasts ++ mymsgs) /= [] then delayinput ++ [mybcasts ++ mymsgs] else delayinput mymsgs = map (msg_setids myid destinationid) (findmsgs messages destinationid myid) mybcasts = map (msgbcast_setfromid myid) (findbcasts broadcasts sourceid ti)

findbcasts :: [Msg_t] -> Int -> Time -> [Msg_t] findbcasts [] sourceid ti = [] findbcasts (f:r) sourceid ti | (msg_isbroadcast f) && ((msg_getfromid f) == sourceid) && (broadcast_is_tradedata (msg_getbroadcast f)) = (f : findbcasts r sourceid ti) | (msg_isbroadcast f) && ((msg_getfromid f) == sourceid) && (broadcast_is_orderlist (msg_getbroadcast f)) = (f : findbcasts r sourceid ti) | otherwise = findbcasts r sourceid ti

-- filter out debug and data messages, only check msg_isorder, and maybe msg_isack findmsgs :: [Msg_t] -> Int -> Int -> [Msg_t] findmsgs [] destinationid myid = [] findmsgs (f:r) destinationid myid | ((msg_getid f) == myid) && (msg_isorder f) = (f : findmsgs r destinationid myid) | ((msg_getid f) == myid) && (msg_istrade f) = (f : findmsgs r destinationid myid) | otherwise = findmsgs r destinationid myid#

8.2.8. Sim_orderlist.hs+ module Sim_orderlist where import Order import Comm

------ORDERLIST

--The bids and offers will be subject to the same ordering criterion (which we may wish to vary later) so make a generic abstype for inserting and deleting orders from the data structure --implementation of orderlist

instance C_Orderlist Orderlist where emptyorderlist x = ([], x)

ol_first ([],bidorask) = (0,[]) ol_first ((x:xs),bidorask) = x

ol_last ([],bidorask) = (0,[]) ol_last ([x],bidorask) = x ol_last ((x:xs),bidorask) = ol_last (xs,bidorask)

isemptyorderlist ([],bidorask) = True isemptyorderlist (any,bidorask) = False

isreallyemptyorderlist ([],bidorask) = True isreallyemptyorderlist (any,bidorask) = isemptyorderlist (ol_clean (any,bidorask))

ol_gettype (x,bidorask) = bidorask

ol_insert p ([],bidorask) o = ([(p,[o])],bidorask) ol_insert p (((p1,xs):ys),bidorask) o | p == p1 = ((p1,newxs):ys,bidorask) | bidorask==Bids = if p > p1 then (((p,[o]):((p1,xs):ys)),Bids) else (((p1,xs): (fst (ol_insert p (ys,Bids) o))),Bids) | bidorask==Asks = if p1 > p then (((p,[o]):((p1,xs):ys)),Asks) else ((p1,xs): (fst (ol_insert p (ys,Asks) o)),Asks) where newxs = insert o xs insert o [] = [o] insert x (y:ys) = if (order_gettime x) < (order_gettime y) -- timeorder

72# then x:(y:ys) else y:(insert x ys)

ol_delete p ([],bidorask) o = ([],bidorask) ol_delete p (((p1,xs):ys),bidorask) o | p==p1 = ((p1,newxs):ys,bidorask) | bidorask==Bids = if p > p1 then (((p1,xs):ys),Bids) else ((p1,xs):(fst (ol_delete p (ys,Bids) o)),Bids) | bidorask==Asks = if p1 > p then (((p1,xs):ys),Asks) else ((p1,xs):(fst (ol_delete p (ys,Asks) o)),Asks) where newxs = delete o xs delete o [] = [] delete x (y:ys) = if (order_samesignature x y) then ys else y:(delete x ys) ol_replace p ([],bidorask) o = ([],bidorask) ol_replace p (((p1,xs):ys),bidorask) o | p==p1 = ((p1,newxs):ys,bidorask) | bidorask==Bids = if p > p1 then (((p1,xs):ys),Bids) else ((p1,xs):(fst (ol_replace p (ys,Bids) o)),Bids) | bidorask==Asks = if p1 > p then (((p1,xs):ys),Asks) else ((p1,xs):(fst (ol_replace p (ys,Asks) o)),Asks) where newxs = replace o xs replace o [] = [] replace x (y:ys) = if (order_samesignature x y) then (x:ys) else y: (replace x ys)

ol_deleteselected ([], bidorask) f = (([],bidorask),[]) ol_deleteselected (ticks,bidorask) f = ((newticks, bidorask),ordersdeleted) where newticks = map g ticks g (p,os) = (p, (filter (not . f) os)) -- keep those that FAIL the test ordersdeleted = concat (map gg ticks) gg (p,os) = filter f os -- keep those that PASS the test

ol_gethighestprice ([],bidorask) = error "Can't get highest price in empty list of orders" ol_gethighestprice ([(p,x)],bidorask) = p ol_gethighestprice (((p,x):xs),Bids) = p ol_gethighestprice (((p,x):xs),Asks) = ol_gethighestprice (xs,Asks) ol_getlowestprice ([],bidorask) = error "Can't get lowest price in empty list of orders" ol_getlowestprice ([(p,xs)],bidorask) = p ol_getlowestprice (((p,x):xs),Asks) = p ol_getlowestprice (((p,x):xs),Bids) = ol_getlowestprice (xs, Bids) ol_getbestprice ([],bidorask) = error "Can't get best price in empty list of orders" ol_getbestprice (((p,[]):xs),bidorask) = ol_getbestprice (xs,bidorask) ol_getbestprice (((p,x):xs),bidorask) = p ol_getliquidity ([],bidorask) = 0 ol_getliquidity (((p,os):xs),bidorask) = (foldr (+) 0 (map order_getsize os)) + (ol_getliquidity (xs,bidorask)) ol_removeliquidity ([],ty) o = ([],ty) ol_removeliquidity (((p,os):xs),ty) o = if (msize >= psize) then ol_removeliquidity (xs,ty) newo else (((p,newos):xs), ty) where msize = order_getsize o psize = foldr (+) 0 (map order_getsize os) newo = order_newsize o (msize-psize)

73# newos = g os o g [] m = [] g (z:zs) m = if (msize < zsize) then (newz:zs) else g zs newm where newz = order_newsize z (zsize - msize) newm = order_newsize m (msize - zsize) msize = order_getsize m zsize = order_getsize z ol_getnumberoforders (any,bidorask) = foldr (+) 0 (map ((length).snd) any) ol_getlevels ([],bidorask) = 0 ol_getlevels (any,bidorask) = length any

-- We define orderbook list depth as the sum of sizes of orders sitting at one price level at one end of the book -- We need to take an ordertype parameter to decide whether to look at the lowest price on the orderbook list (Offers) -- or the highest price o the orderbook list (Bids) -- AGC 27/01/2015: now has an extra parameter which dictates whether the orderlist is a list of bids or asks, -- so the first parameter is now redundant, and the best price is always at the head of the list ol_getdepth ty ([], bidorask) = 0 ol_getdepth ty (((p,xs):ys), bidorask) = foldr (+) 0 (map order_getsize xs)

-- We define orderbook list depth near top" as the sum of sizes of orders sitting at one price level at one end of the book -- plus sizes of other orders sitting on book with a price within X% of the top price. -- We need to take an ordertype parameter to decide whether to look at the lowest price on the orderbook list (Offers) -- or the highest price o the orderbook list (Bids) ol_getdepthneartop ty percent ([],bidorask) = 0 ol_getdepthneartop ty percent (((p,xs):ys),Asks) = (sumsizes xs) + (f p ys) where sumsizes os = foldr (+) 0 (map order_getsize os) f p [] = 0 f p ((p1,xs1):ys) = if (p1<(p*(1+percent))) then (sumsizes xs1) + (f p ys) else 0 ol_getdepthneartop ty percent (((p,xs):ys),Bids) = (sumsizes xs) + (f p ys) where sumsizes os = foldr (+) 0 (map order_getsize os) f p [] = 0 f p ((p1,xs1):ys) = if (p1>(p*(1-percent))) then (sumsizes xs1) + (f p ys) else 0

ol_poplowest ([],bidorask) = error "Can't pop lowest order from an empty list of orders" ol_poplowest (((p,[]):ys),bidorask) = ol_poplowest (ys,bidorask) ol_poplowest (((p,(x:xs)):ys),bidorask) = (x, (((p,xs):ys),bidorask)) ol_clean (any,bidorask) = (isort (filter (((/=[]).snd)) any) [], bidorask) where isort [] any = any isort (x:xs) any = isort xs (insert x any bidorask) insert x [] bidorask = [x] insert (a,b) ((c,d):ys) Bids = if a>c then (a,b):((c,d):ys) else (c,d):(insert (a,b) ys Bids) insert (a,b) ((c,d):ys) Asks = if a

-- -- ol_fill takes a list of resting limit orders, a market order, a (Buy Andkill)/(Sell Andkill) indicator and a list of trades -- - The (Buy Andkill)/(Sell Andkill) indicator tells us in which direction to search the order list -- - The list of trades should start off as empty, since it is the list of fills to satisfy the market order -- ol_fill returns the remaining order list after removing the fills, the remaining market order if it wasn't competely filled, -- and the list of fills (the trades) -- ol_fill ([],bidorask) m any tr = (emptyorderlist bidorask, m, tr)

74# ol_fill (((p2,[]):ys),bidorask) m any tr --easy - head of list is lowest (Offer Goodtillcancelled) - try it first = ol_fill (ys,bidorask) m any tr ol_fill (((p2, (x:xs)):ys), bidorask) m any tr | isemptyorder m = ((((p2,(x:xs)):ys),bidorask), emptyorder, tr) | msize == xsize = ((((p2,xs):ys),bidorask), emptyorder, newtr2) | msize < xsize = ((((p2,(newx:xs)):ys),bidorask), emptyorder, newtr2) | otherwise = ol_fill (((p2,xs):ys),bidorask) newm any newtr where xsize = order_getsize x msize = order_getsize m newm = order_newsize m (msize - xsize) newtr = (x, (order_newprice (order_newsize m xsize) (order_getprice x))): tr newx = order_newsize x (xsize - msize) newtr2 = (order_newsize x msize, (order_newprice m (order_getprice x))):tr

-- -- ol_fill_cross is used for a crossed book. In this case the market order isn't really a market order - it is -- an (Offer Goodtillcancelled) limit order that is crossed with a (Bid Goodtillcancelled) limit order. We therefore execute at the mean price. -- Also, we have to keep checking after each execution whether the book is still crossed or not - we no longer -- have access to the book, so we check whether (mprice > xprice) which would mean no longer crossed.

ol_fill_cross ([],bidorask) m any tr = (emptyorderlist bidorask, m, tr) ol_fill_cross (((p2,[]):ys),bidorask) m (Buy Andkill) tr --easy - head of list is lowest (Offer Goodtillcancelled) - try it first = ol_fill_cross (ys,bidorask) m (Buy Andkill) tr ol_fill_cross (((p2, (x:xs)):ys),bidorask) m (Buy Andkill) tr | mprice > xprice = ((((p2,(x:xs)):ys),bidorask), m, tr) | isemptyorder m = ((((p2,(x:xs)):ys),bidorask), emptyorder, tr) | msize == xsize = ((((p2,xs):ys),bidorask), emptyorder, newtr2) | msize < xsize = ((((p2,(newx:xs)):ys),bidorask), emptyorder, newtr2) | otherwise = ol_fill_cross (((p2,xs):ys),bidorask) newm (Buy Andkill) newtr where xsize = order_getsize x msize = order_getsize m xprice = order_getprice x mprice = order_getprice m executeprice = (mprice + xprice)/2 newm = order_newsize m (msize - xsize) newtr = (order_newprice x executeprice, (order_newprice (order_newsize m xsize) executeprice)): tr newx = order_newsize x (xsize - msize) newtr2 = (order_newprice (order_newsize x msize) executeprice, (order_newprice m executeprice)):tr ol_fill_cross os m (Sell Andkill) tr = ol_fill_cross (ol_reverse os) m (Buy Andkill) tr ol_fill_cross os m any tr = error "Cannot fill crossed order - (Offer Goodtillcancelled) not provided"

ol_reverse ([],bidorask) = ([],bidorask) ol_reverse ((x:xs),bidorask) = (reverse (x:xs),bidorask)

xshoworderlist ([], bidorask) = "" xshoworderlist (((p,xs):ys), bidorask) = (show p) ++ ": " ++ (concat (map showorder xs)) ++ "\n" ++ (xshoworderlist (ys, bidorask))

showorderlist ([],bidorask) = "" showorderlist (x, Bids) = "" ++ (xshoworderlist (x, Bids)) showorderlist (x, Asks) = "" ++ (xshoworderlist (x, Asks))

#

8.2.9. MyTrader.hs+ # module MyTrader where import Comm import Agent import Sim_orderlist import Debug.Trace

--MyTrader

75# size = 100 -- order size

-- Information: ------

-- returns list of orders to be sent to each exchange

-- gets the lowest n (size) orders from each exchange

-- returns orders for exchanges

mytraderwrapper :: Agent_t mytraderwrapper (Emptyagentstate) args any myid = mytraderwrapper (Mytraderagstate ([0], getsent, (map (order_setuid "mytraderwrapper") [0..]), (map fromIntegral(drop 15 rnds)), [])) args any myid where rnds = drop myid randoms getsent| (arg_getstr (si "eerc:1" args 0)) == "Calm" = Calm | (arg_getstr (si "errc:2" args 0)) == "Choppy" = Choppy | (arg_getstr (si "errc:3" args 0)) == "Ramp" = Ramp | (arg_getstr (si "errc:4" args 0)) == "Toxic" = Toxic | otherwise = error "Unrecognised sentiment." mytraderwrapper (Mytraderagstate ([invent], sent, uids, rnds, any)) args ((ti, messages, broadcasts) : simstateinfos) myid = trace "mytrader1" ((myexchmsgs ++ otherexchmsgs) : (mytraderwrapper (Mytraderagstate ([newinvent], sent, remaininguids2, (drop 15 rnds), any)) args simstateinfos myid)) where myexchmsgs = if ti < 1 then (map (ordermessage (myid, myexchid)) fmyorders) else [Hiaton] otherexchmsgs = if ti < 1 then (map (ordermessage (myid, otherexchid)) fotherorders) else [Hiaton] (remaininguids1, fmyorders) = applyuids uids myexchorders (remaininguids2, fotherorders) = applyuids remaininguids1 otherexchorders mytrades = map (cpsafehd "frwrapper1") (filter (not.null) (map msg_gettrade messages)) newinvent = foldr (+) invent (map getmovement mytrades) where getmovement o |(isBuySide o) = (order_getsize o) |(isSellSide o) = (- (order_getsize o)) |otherwise = error "frwrapper - getmovement - order type not recognised."

myexchorders = [order_create 1997 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 1999 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2001 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2003 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2006 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2009 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2010 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2012 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2015 25 ti (HFT myid) (Offer Goodtillcancelled)] otherexchorders = [order_create 2000 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2002 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2005 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2007 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2011 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2013 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2016 25 ti (HFT myid) (Offer Goodtillcancelled), order_create 2018 25 ti (HFT myid) (Offer Goodtillcancelled)]

(myexchid, otherexchid) = (fr1exchid, fr2exchid)

#

76# 8.2.10. Makefile+ # Main: Agent.hs Baserands.hs Broker.hs Comm.hs Delay.hs Frontrunner.hs Fundamentals.hs Hft.hs LaggedHft.hs Main.hs Messages.hs MyTrader.hs NewHft.hs Nicemime.hs Noiseagent.hs Order.hs Sim.hs Sim_lob.hs Sim_orderlist.hs Stats.hs TestHarness.hs Traders.hs ghc Main.hs -o Main -odir output -hidir output #

8.2.11. Main.hs+ # module Main where import TestHarness main::IO() main = testfrontrunning# #

8.2.12. Nicemime.hs+(the+exchange)+Snippet+ # module Nicemime(nice_mime_wrapper) where import Comm import Agent import Order import Debug.Trace

--nicemime percent = 0.05 --For bs/ss depth near top. percentleeway = 0.05 -- Accept no orders beyond this leeway pricebandingvariation :: Double pricebandingvariation = 12 --Price banding - Any new limit order must be within -+ 12.0 (48 ticks) of the last traded price. spiketrigger :: Double spiketrigger = 600 ordermax::Double ordermax = 2000 -- cmegroup.com E-mini FAQ defmrt::Int defmrt = 0 -- Minimum resting time. maxordersallowed :: Double maxordersallowed = 1000000 -- Total allowed shares on book for any one agent.

--nice_mime takes its old state, a list of orders, its own ID and a list of cancellations and returns a new state and a list of outgoing messages --It does this by first pruning the book for expired entries and cancelled ones, then it places the new limit orders on the book, then uncrosses the book, --and finally attempts to execute all the market orders it received as well. nice_mime :: Nice_mime_lob -> [Order] -> Int -> [(Int,Int)] -> Time -> (Nice_mime_lob, [Msg_t]) nice_mime reallyoldlob orders myid cancellations mrt -- If the lob is not spiked then just return the final state of the new lob as well as all the messages generated. | isspiked == False = (flob, tmsg : ibmsg : bmsg : bidmsg : offermsg : (msgs1 ++ msgs2 ++ msgs3 ++ cmsgs)) -- If the lob is spiked then only return the log with limit orders appended and the relevent messages including a rejection to all market orders. | isspiked == True = (fstlob, stmsg : sbmsg : (msgs1 ++ cmsgs ++ rejectallmorders ++ spikecast)) where rejectallmorders = (map spikerejectorder morders) (oldlob, isspiked) = nice_mime_lob_isspiked reallyoldlob spikecast = [(broadcastmessage (myid,myid-1) (broadcast_str (Str "The order book is spiking.")))] sbmsg = (broadcastmessage (myid,myid-1) (broadcast_numlist (nice_mime_lob_getsummary fstlob ((length tsnorders) + (length morders))))) stmsg =if (nice_mime_lob_gettime reallyoldlob) /= (-1) then (datamessage (myid,myid-1) (nice_mime_lob_gettrace fstlob)) else (datamessage (myid,myid-1) ((nice_mime_lob_gettraceheaders))) bmsg = (broadcastmessage (myid,myid-1) (broadcast_numlist (nice_mime_lob_getsummary flob ((length tsnorders) + (length morders))))) bcast_numlist :: Broadcast_t -- really weird, type ambiguous bcast_numlist = broadcast_numlist (nice_mime_lob_getsummary fstlob ((length tsnorders) + (length morders))) ibmsg = (debugmessage (myid,myid-1) (show bcast_numlist)) -- CDC 2014

77# bidmsg = if isspiked == False -- AGC 2015 then (broadcastmessage (myid,myid-1) (broadcast_orderlist (nice_mime_lob_getbids flob))) else (broadcastmessage (myid,myid-1) (broadcast_orderlist (nice_mime_lob_getbids fstlob))) offermsg = if isspiked == False -- AGC 2015 then (broadcastmessage (myid,myid-1) (broadcast_orderlist (nice_mime_lob_getoffers flob))) else (broadcastmessage (myid,myid-1) (broadcast_orderlist (nice_mime_lob_getoffers fstlob))) tmsg = if (nice_mime_lob_gettime reallyoldlob) /= (-1) then (datamessage (myid,myid-1) (nice_mime_lob_gettrace flob)) else (datamessage (myid,myid-1) ((nice_mime_lob_gettraceheaders))) (tsnorders, morders) = ((filter (myor (isOtype "Bid") (isOtype "Offer")) ts_orders), (filter ((myor (myor ((==) (Sell Andkill)) ((==) (Sell Orkill)) ) (myor ((==) (Buy Andkill)) ((==) (Buy Orkill)) )).order_gettype) ts_orders)) where ts_orders = zipfunc (map order_setfractime [0..]) orders --fractional timestamped orders (prunedlob, cmsgs) = nice_mime_lob_prune (nice_mime_lob_incrementtime oldlob) cancellations myid mrt (fstlob, msgs1) = (nice_mime_lob_appendorders prunedlob tsnorders myid mrt) (sndlob, msgs2) = (nice_mime_lob_uncross_book fstlob myid) flob = (nice_mime_lob_updatestats wlob) (wlob, msgs3) = executeMorders sndlob morders where executeMorders mylob [] = (mylob, []) executeMorders mylob (top:tail) = returntuple where returntuple = if isspiked == False then (myflob, messages ++ rest) else (myflob, rest) (myilob, messages, order) = if top /= emptyorder then nice_mime_lob_execute_order mylob top myid else error ("nice_mime - top is an empty order.") (myflob, rest) = if isspiked == False then executeMorders myilob tail else (pslob, (map spikerejectorder (top:tail))) (pslob, isspiked) = nice_mime_lob_triggerspike mylob top --pslob = potentially spiked lob spikerejectorder ordr = (ackmessage (myid, (order_gettraderidno ordr)) 6 ordr "Temporarily stopped trading. Stop-spike protection triggered.") nice_mime_lob_gettime (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) = time

--4. The book is now checked to see if it is crossed and if so, uncrossed. (nice_mime_lob_uncross_book) -- a. If there are no bids, no offers or the book is not crossed then just return the state received. -- b. Otherwise, take the best bid and execute it -- -- TEMPORARILY DISABLED - CDC 4/4/2014 -- nice_mime_lob_uncross_book :: Nice_mime_lob -> Int -> (Nice_mime_lob, [Msg_t]) nice_mime_lob_uncross_book (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) myid = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), []) -- , if or [(bids = []), (offers = [])] --nice_mime_lob_uncross_book lob myid = (lob, []), if (nice_mime_lob_getbestbid lob) < (nice_mime_lob_getbestoffer lob) -- = (finallob, moremessages ++ messages), otherwise -- where -- (finallob, moremessages) = nice_mime_lob_uncross_book newlob myid -- (newlob, messages, retorder) = (nice_mime_lob_execute_order lob (nice_mime_lob_getleaderfrombids lob) myid), if (nice_mime_lob_getleaderfrombids lob) ~= emptyorder --May want to do something with retorder... -- = error ("nice_mime_lob_uncross_book - getleaderfrombids returned emptyorder " ++ (show lob)), otherwise shownice_mime_lob (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) = "\nNice_mime_lob @ t" ++ (show time) ++ "\nlast traded price: " ++ (show ltp) ++ "\nbids: " ++ (show bids) ++ "\noffers: " ++ (show offers)

-- nice_mime_lob_execute_order --i. This takes an order and executes trades between it and the leading orders on the opposite side. --ii. It updates/removes orders as it executes trades and creates the relevant trade messages (trademessage). --iii. The price traded at is the price specified by the older of the two messages. (Hence the fractional times mentioned earlier) --iv. Many specific cases, each is presented in the where block below. nice_mime_lob_execute_order :: Nice_mime_lob -> Order -> Int -> (Nice_mime_lob, [Msg_t], Order) --order is remaining order. nice_mime_lob_execute_order (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) order myid |(not (nice_mime_lob_checkorderallowed totlist order)) && (or [((order_gettype order) == (Buy Andkill)), ((order_gettype order) == (Sell Andkill))]) = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [(ackmessage (myid, (order_gettraderidno order)) 1 order "buy/sell was too big.")], order) |(or [(not (nice_mime_lob_checkorderallowed totlist order)), ((nice_mime_lob_getsellsideliquidity (Nice_mime_lob sent totlist bids offers time ticksize ltp sts)) < (order_getsize order))]) && ((order_gettype order) == (Buy Orkill)) = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [(ackmessage (myid, (order_gettraderidno order)) 1 order "buy or kill was too big.")], order) -- (Buy Orkill) too big |(or[(not (nice_mime_lob_checkorderallowed totlist order)), ((nice_mime_lob_getbuysideliquidity (Nice_mime_lob sent totlist bids offers time ticksize ltp sts)) < (order_getsize order))]) && ((order_gettype order) == (Sell Orkill)) = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [(ackmessage (myid, (order_gettraderidno order)) 1 order "sell or kill was too big.")], order) -- (Sell Orkill) too big

78# | otherwise = (finallob, restofmsgs, ro) --Potential problem area for missing messages where

(finallob, restofmsgs, ro) --Cases below

--If the order is a buy or sell and the order has been exhausted then just return the lob & return emptyorder. | ((order_getsize order) == 0) && (or [((order_gettype order) == (Buy Andkill)),((order_gettype order) == (Sell Andkill)), ((order_gettype order)== (Sell Orkill)), ((order_gettype order) == (Buy Orkill))]) = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [(ackmessage (myid, (order_gettraderidno order)) 0 order "")], emptyorder)

--If you've run out of liquidity on a side and you're dealing with a limit order just return. | or [(isOtype "Offer" order && isemptyorderlist bids),(isOtype "Bid" order && isemptyorderlist offers)] = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [], order)

--If you've run out of liquidity on a side and you're dealing with a X and kill market order then return reject. | or [(isOtype "Sell" order && isemptyorderlist bids),(isOtype "Buy" order && isemptyorderlist offers)] = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), [(ackmessage (myid, (order_gettraderidno order)) 2 order "no liquidity on opposite side.")], order)

--If the order is a bid and no liquidity remains on the first sell side level then return the lob without the exhausted level & remaining order. | (snd (ol_first offers) == []) && (isOtype "Bid" order) = ((Nice_mime_lob sent totlist nbids (ol_clean offers) time ticksize ltp sts), [], order)

--If the order is a (Buy Andkill) and no liquidity remains on the first sell side level then continue iterating without the exhausted level. | ((order_gettype order) == (Buy Andkill)) && ((snd (ol_first offers)) == []) = nice_mime_lob_execute_order (Nice_mime_lob sent totlist bids (ol_clean offers) time ticksize ltp sts) order myid

--If the order is an offer and no liquidity remains on the first buy side level then return the lob without the exhausted level & remaining order. | (isOtype "Offer" order) && ((snd (ol_first bids)) == []) = ((Nice_mime_lob sent totlist (ol_clean bids) noffers time ticksize ltp sts), [], order)

--If the order is a (Sell Andkill) and no liquidity remains on the first sell buy level then continue iterating without the exhausted level. | ((snd (ol_first bids)) == []) && ((order_gettype order) == (Sell Andkill)) = nice_mime_lob_execute_order (Nice_mime_lob sent totlist (ol_clean bids) offers time ticksize ltp sts) order myid

--If the order has been exhausted and it's not a (Buy Andkill) or a (Sell Andkill) then return the lob with it removed. | ((order_getsize order) == 0) = (tickAndOrderRemovedLob,[], emptyorder)

--If the old order is non-zero then match! (Recall price banding from nice_mime_lob_checkorderallowed ensures that SSL will never be triggered) | ((order_getsize order) > 0) = ((nice_mime_lob_inccumtradevol voltr (nice_mime_lob_inctrades nlob)), msgs ++ nmsgs, forder)

|((order_getsize order) < 0) = error ("nice_mime_lob_execute_order - The order went into the negative." ++ (show order)) |otherwise = error "nice_mime_lob_execute_order - There's something you've missed entirely." where (nlob, nmsgs, forder) = nice_mime_lob_execute_order intermediatelob intermediateorder myid (intermediateorder, norder2, msgs, nltp, voltr) = nice_mime_makeatrade order order2 myid order2 | isBuySide order = fst (ol_poplowest offers) | isSellSide order = fst (ol_poplowest bids) | isemptyorder order = error ("nice_mime_lob_execute_order - Emptyorder " ++ (show order)) nbids = nice_mime_lob_replaceorder1 bids order False noffers = nice_mime_lob_replaceorder1 offers order False tickAndOrderRemovedLob | (isOtype "Bid" order) = (Nice_mime_lob sent totlist (ol_clean removeBid) offers time ticksize ltp sts) | (isOtype "Offer" order) = (Nice_mime_lob sent totlist bids (ol_clean removeOffer) time ticksize ltp sts) | otherwise = error "nice_mime_lob_execute_order - Tried to remove order for a (Sell Andkill) or (Buy Andkill)." removeOffer = if (order_samesignature order (fst (ol_poplowest offers))) then snd (ol_poplowest offers) else error ( "nice_mime_lob_execute_order - Mismatching orders at heads of lists.\n" ++ (show order) ++"\n" ++ (showorder (fst (ol_poplowest offers)))) removeBid = if (order_samesignature order (fst (ol_poplowest bids))) then snd (ol_poplowest bids) else error ( "nice_mime_lob_execute_order - Mismatching orders at heads of lists.\n" ++ (show order) ++"\n" ++ (showorder (fst (ol_poplowest bids)))) -- removeTickAndOrder |not $null(snd (safehd removeOrder "nice_mime_lob_execute_order5")) = removeOrder

79# -- |null (snd (safehd removeOrder "nice_mime_lob_execute_order6")) = (tail removeOrder) -- |otherwise = error "nice_mime_lob_execute_order - Paranoia consoling error for removeTickAndOrder." -- removeOrder = if (order_samesignature order (safehd (snd (safehd otherlist "nice_mime_lob_execute_order10")) "nice_mime_lob_execute_order9")) -- then ((fst (safehd otherlist "nice_mime_lob_execute_order7")), (tail (snd (safehd otherlist "nice_mime_lob_execute_order8")))) : (tail otherlist) -- else error ("nice_mime_lob_execute_order - Mismatching orders at heads of lists.\n" ++ (show order) ++"\n" ++ (show (safehd (snd (safehd otherlist "nice_mime_lob_execute_order10")) "nice_mime_lob_execute_order9")) ) -- (intermediateorder, norder2, msgs, nltp, voltr) = nice_mime_makeatrade order order2 myid -- order2 = (safehd (snd (safehd list "nice_mime_lob_execute_order11")) "nice_mime_lob_execute_order12") -- (nlob, nmsgs, forder) = nice_mime_lob_execute_order intermediatelob intermediateorder myid intermediatelob = nice_mime_lob_setltp nltp (nice_mime_lob_updatetotal (nice_mime_lob_updatetotal notilob order2 norder2) order intermediateorder) notilob|((order_getsize norder2) > 0) && (isSellSide norder2) = (Nice_mime_lob sent totlist bids (nice_mime_lob_replaceorder1 offers norder2 False) time ticksize (order_getprice order2) sts) |((order_getsize norder2) == 0) && (isSellSide norder2) = (Nice_mime_lob sent totlist bids (nice_mime_lob_replaceorder1 offers norder2 True) time ticksize (order_getprice order2) sts) |((order_getsize norder2) > 0) && (isBuySide norder2) = (Nice_mime_lob sent totlist (nice_mime_lob_replaceorder1 bids norder2 False) offers time ticksize (order_getprice order2) sts) |((order_getsize norder2) == 0) && (isBuySide norder2) = (Nice_mime_lob sent totlist (nice_mime_lob_replaceorder1 bids norder2 True) offers time ticksize (order_getprice order2) sts) |otherwise = error "nice_mime_lob_execute_order - intermediate lob could not be generated. intermediate order problems."

-- list |isBuySide order = offers --The opponent list to the order being executed. -- |isSellSide order = bids -- |order == emptyorder = error ("nice_mime_lob_execute_order - Emptyorder " ++ (show order)) -- otherlist| isSellSide order = offers --The list that contains the order being executed. -- | isBuySide order = bids -- | order == emptyorder = error ("nice_mime_lob_execute_order - Emptyorder " ++ (show order)) offersareempty (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) = if (isemptyorderlist offers) then True else False nice_mime_lob_updatetotlist :: [Double] -> Order -> Order -> [Double] nice_mime_lob_updatetotlist totlist oldorder neworder = newtotlist where (Nice_mime_lob sent newtotlist bids offers time ticksize ltp sts) = nice_mime_lob_updatetotal (Nice_mime_lob sent totlist (emptyorderlist Bids) (emptyorderlist Asks) (-1) 25 1700 []) oldorder neworder nice_mime_lob_setltp nltp (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) = (Nice_mime_lob sent totlist bids offers time ticksize nltp sts)

nice_mime_lob_updatetotal (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) oldorder neworder = (Nice_mime_lob sent newtotlist bids offers time ticksize ltp sts) where extendedtotlist = if (length totlist) > trid+1 then totlist else totlist ++ (rep (trid+1 - (length totlist)) 0) newtotlist = (take trid extendedtotlist) ++ [newvalue] ++ (drop (trid+1) extendedtotlist) trid = order_gettraderidno neworder difference = if or [order_samesignature neworder oldorder, oldorder == emptyorder] then (order_getsize oldorder) - (order_getsize neworder) else error "nice_mime_lob_updatetotal - Orders don't match!" newvalue | isBuySide neworder = (extendedtotlist!!trid) + difference | isSellSide neworder = (extendedtotlist!!trid) - difference

-- This function searches for an order (initially by price) and either deletes it or replaces it nice_mime_lob_replaceorder1 :: Orderlist -> Order -> Bool -> Orderlist --Bool = delete if True replace if False nice_mime_lob_replaceorder1 olist iorder True = ol_delete (order_getprice iorder) olist iorder nice_mime_lob_replaceorder1 olist iorder False = ol_replace (order_getprice iorder) olist iorder

nice_mime_lob_replaceorder :: [Tick] -> Order -> Bool -> [Tick] --Bool = delete if True replace if False nice_mime_lob_replaceorder list iorder flag = newlist where order = if flag == True then [] else [iorder] newlist = if tindex /= -1 then (take tindex list) ++ newtick ++ (drop (tindex + 1) list) else error ("nice_mime_lob_replaceorder - findindexoffirst failed " ++ (show list)++ "\n" ++ (show iorder)) tindex = findindexoffirst list ((== (order_getprice iorder)).fst) -- not sure

80# newtick = if oindex /= -1 then [((order_getprice iorder),(take oindex olist) ++ order ++ (drop (oindex + 1) olist))] else error ("nice_mime_lob_replaceorder - findindexoffirst failed " ++ (show olist) ++ "\n" ++ (show iorder)) olist = if tindex /= -1 then snd (list!!tindex) else error ("nice_mime_lob_replaceorder - findindexoffirst failed " ++ (show list)++ "\n" ++ (show iorder)) oindex = findindexoffirst olist (order_samesignature iorder)

-- nice_mime_lob_isspiked checks to see if the lob state passed as an argument is spiked. -- If so it decrements one from the remaining spike time and returns the new state & a boolean indicating that the lob is spiked. -- Otherwise it just returns the state it received as well as False. nice_mime_lob_isspiked :: Nice_mime_lob -> (Nice_mime_lob,Bool) nice_mime_lob_isspiked (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) | (length sts) < 31 = error "nice_mime_lob_isspiked - stats too " | (sts!!30) /= 0 = (nlob, True) | otherwise = ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), False) where nlob = (Nice_mime_lob sent totlist bids offers time ticksize ltp (replace 30 sts ((sts!!30) - 1))) nice_mime_lob_triggerspike :: Nice_mime_lob -> Order -> (Nice_mime_lob,Bool) nice_mime_lob_triggerspike (Nice_mime_lob sent totlist bids offers time ticksize ltp sts) morder = if consensus == True then (newlob,consensus) else ((Nice_mime_lob sent totlist bids offers time ticksize ltp sts), consensus) where newlob = (Nice_mime_lob sent totlist bids offers time ticksize ltp (replace 30 sts (secondstosteps 4))) consensus = if or [((finaltradedprice >= (ltp - spiketrigger)) && (finaltradedprice <= (ltp + spiketrigger))), (finaltradedprice == (-1))] then False else True finaltradedprice | isBuySide morder = getfinaltradedprice2 offers morder (-1) | isSellSide morder = getfinaltradedprice2 bids morder (-1) | otherwise = error ("triggerspike1" ++ (show morder)) where getfinaltradedprice1 ticks orderleft lastprice = if or [(orderleft < 0), (ticks == [])] then lastprice else getfinaltradedprice1 tickrest neworderleft tickprice where tickrest = (tail ticks) tickprice = (fst (head ticks)) neworderleft = orderleft - tickfullsize tickfullsize = (foldr (+) 0 (map order_getsize orders)) orders = (snd (head ticks)) getfinaltradedprice2 olist morder lastprice = if or [((order_getsize morder) < 0), (isemptyorderlist newolist)] then lastprice else ol_getbestprice newolist where newolist = (ol_removeliquidity olist morder)

nice_mime_makeatrade :: Order -> Order -> Int -> (Order, Order, [Msg_t], Double, Double) nice_mime_makeatrade order1 order2 myid = (norder1, norder2, [(trademessage (myid, (exch_getdelaysfromtraderids myid (order_gettraderidno order1))) cnorder1 cnorder2), (trademessage (myid, (exch_getdelaysfromtraderids myid (order_gettraderidno order2))) cnorder2 cnorder1), (broadcastmessage (myid,myid-1) (broadcast_tradedata (tradeprice, tradedvol)))], tradeprice, tradedvol) where tradeprice = getrestingprice order1 order2 cnorder1 = order_newsize (order_setprice tradeprice norder1) order1diff --Order with corrected price. cnorder2 = order_newsize (order_setprice tradeprice norder2) order2diff --Order with corrected price. norder1 = if ((order_getsize order1) - (order_getsize order2)) <= 0 then order_newsize order1 0 else order_newsize order1 ((order_getsize order1) - (order_getsize order2)) norder2 = if ((order_getsize order2) - (order_getsize order1)) <= 0 then order_newsize order2 0 else order_newsize order2 ((order_getsize order2) - (order_getsize order1)) order1diff = (order_getsize order1) - (order_getsize norder1) --Traded amount order2diff = (order_getsize order2) - (order_getsize norder2) --Traded amount tradedvol = order_getsize cnorder2

nice_mime_emptylob = Nice_mime_lob Calm [] (emptyorderlist Bids) (emptyorderlist Asks) (-1) 25 2000 (rep 34 0)

81# nice_mime_lob_inctrades (Nice_mime_lob sent totlist bids offers time ticksize ltp (tr:rest)) = (Nice_mime_lob sent totlist bids offers time ticksize ltp ((tr+1):rest)) nice_mime_wrapper :: Agent_t nice_mime_wrapper state args ((time, messages, broadcasts) : simstateinfos) myid = trace "nice_mime" (msgs : nice_mime_wrapper (Nicemimestate newstate) args simstateinfos myid) where mymrt = if (arg_findval "MinimumRestingTime" args) /= (-1) then round $arg_findval "MinimumRestingTime" args else defmrt checkstate = if state == Emptyagentstate then nice_mime_lob_setsent getsent (nice_mime_emptylob) else (internalstate state) -- look here where internalstate (Nicemimestate astate) = astate (newstate, msgs) = nice_mime checkstate orders myid (concat (map msg_getcanceltuple messages)) mymrt orders = (filterorders messages) where filterorders qx = msg_getorders qx getsent |(arg_getstr (args!!0)) == "Calm" = Calm |(arg_getstr (args!!0)) == "Choppy" = Choppy |(arg_getstr (args!!0)) == "Ramp" = Ramp |(arg_getstr (args!!0)) == "Toxic" = Toxic |otherwise = error "Unrecognised sentiment." nice_mime_lob_setsent sent (Nice_mime_lob osent totlist bids offers time ticksize ltp sts) = (Nice_mime_lob sent totlist bids offers time ticksize ltp sts)# # #

82# 8.3. User(Manual(

8.3.1. Compilation( # By#using#this#GNU#Haskell#compiler#command#with#the#following#flags,#the# header#and#output#files#generated#will#be#gathered#into#a#separate#folder#called# ‘output’.# # ghc Main.hs -o Main -odir output -hidir output

There#is#also#a#‘makefile’#included#that#uses#this#build#string,#which#can#be#used# by#entering#the#‘make’#command#in#the#directory.#

8.3.2. Running(an(Experiment( # The#Main.hs#module#appears#as#below,#where#‘testfrontrunning’#can#be#changed# to#any#of#the#functions#in#the#TestHarness.hs#module.#After#compiling,#simply#run# Main.hs#by#entering#./Main.hs#into#the#command#line.#The#tracefiles#folder#will#be# populated#with#the#tracefiles#for#the#experiment.# # module Main where import TestHarness main::IO() main = testfrontrunning

8.3.3. Altering(the(Variables(of(an(experiment(

8.3.3.1. Delay*Sizes* # The#only#code#that#needs#to#be#edited#to#set#up#any#frontGrunning#experiment#is# Agent.hs.#To#change#delay#sizes#of#an#experiment,#edit#the#values#in#the#‘Delay# amounts’#section#of#the#module.#An#example#is#shown#below:# # -- Delay amounts fr2tofr1delay = 1 -- from fr2 to fr1 fr1tofr2delay = 1 -- from fr1 to fr2 exch1tofr1delay = 1 exch2tofr2delay = 9 broker1toexch1delay = 1 broker1toexch2delay = broker1toexch1delay + 9 + (max (exch1tofr1delay + fr1tofr2delay + fr2toexch2delay) (exch1tofr3delay + fr3tofr4delay + fr4toexch2delay)) exch1tobroker1delay = broker1toexch1delay exch2tobroker1delay = broker1toexch2delay fr1toexch1delay = exch1tofr1delay fr2toexch2delay = exch2tofr2delay broker2toexch1delay = broker2toexch2delay + 9 + (max (exch1tofr1delay + fr1tofr2delay + fr2toexch2delay) (exch1tofr3delay + fr3tofr4delay + fr4toexch2delay)) broker2toexch2delay = 1 exch1tobroker2delay = broker2toexch1delay exch2tobroker2delay = broker2toexch2delay fr4tofr3delay = 1 fr3tofr4delay = 1 exch1tofr3delay = 9 exch2tofr4delay = fr2toexch2delay

83# fr3toexch1delay = exch1tofr3delay fr4toexch2delay = 1

8.3.3.2. Repeating*the*Above*Simulations* # The#infrastructure#has#been#put#in#place#to#run#the#experiments#detailed#in#this# report#by#simply#editing#the#following#lists#in#the#‘Agent#lists’#section#of#Agent.hs:# # exchange_list = [fr1exchid,fr2exchid] broker_list = [broker1id] frontrunner_list = [fr1id,fr2id,fr3id,fr4id]

For#example,#to#add#a#second#broker,#simply#change#the#broker_list#to# [broker1id,#broker2id],#and#to#remove#a#frontGrunner,#change#frontrunner_list#to# [fr1id,#fr2id].# # The#agent#should#also#be#added#or#removed#from#the#id#list#below,#ensuring#that# each#of#the#ids#is#consecutively#increasing#by#integer#amounts#from#1:# # fr2tofr1delayid = 1 fr1tofr2delayid = 2 exch1tofr1delayid = 3 exch2tofr2delayid = 4 broker1toexch1delayid = 5 broker1toexch2delayid = 6 exch1tobroker1delayid = 7 exch2tobroker1delayid = 8 fr1toexch1delayid = 9 fr2toexch2delayid = 10 broker2toexch1delayid = 11 broker2toexch2delayid = 12 exch1tobroker2delayid = 13 exch2tobroker2delayid = 14 fr4tofr3delayid = 15 fr3tofr4delayid = 16 exch1tofr3delayid = 17 exch2tofr4delayid = 18 fr3toexch1delayid = 19 fr4toexch2delayid = 20 fr1exchid = 21 -- exch1 id fr2exchid = 22 -- exch2 id fr1id = 23 fr2id = 24 fr3id = 25 fr4id = 26 broker1id = 27 broker2id = 28 #

8.3.3.3. Creating*More*Complex*Simulations* # To#run#a#simulation#with#more#than#2#frontGrunners#or#brokers,#further#changes# to#the#infrastructure#of#the#code#is#required,#but#all#changes#are#limited#only#to# Agent.hs.## # As#well#as#amending#the#lists#in#Section#8.3.3.2,#the#new#agent#should#have#the# appropriate#delays#added#to#the#delay_list,#and#the#‘receiving#from’#and#‘sending# to’#ids#listed#in#the#delay_init_list,#in#accordance#with#the#proposed#setup:#

84# # -- delayid delay_list = [fr2tofr1delay, -- 1 fr1tofr2delay, -- 2 exch1tofr1delay, -- 3 exch2tofr2delay, -- 4 broker1toexch1delay, -- 5 broker1toexch2delay, -- 6 exch1tobroker1delay, -- 7 exch2tobroker1delay, -- 8 fr1toexch1delay, -- 9 fr2toexch2delay, -- 10 broker2toexch1delay, -- 11 broker2toexch2delay, -- 12 exch1tobroker2delay, -- 13 exch2tobroker2delay, -- 14 fr4tofr3delay, -- 15 fr3tofr4delay, -- 16 exch1tofr3delay, -- 17 exch2tofr4delay, -- 18 fr3toexch1delay, -- 19 fr4toexch2delay] -- 20 delay_init_list = [(fr2id,fr1id), (fr1id,fr2id), (fr1exchid,fr1id), (fr2exchid,fr2id), (broker1id,fr1exchid), -- (sender,destination) (broker1id,fr2exchid), (fr1exchid,broker1id), (fr2exchid,broker1id), (fr1id,fr1exchid), (fr2id,fr2exchid), (broker2id,fr1exchid), (broker2id,fr2exchid), (fr1exchid,broker2id), (fr2exchid,broker2id), (fr4id,fr3id), (fr3id,fr4id), (fr1exchid,fr3id), (fr2exchid,fr4id), (fr3id,fr1exchid), (fr4id,fr2exchid)]# # # # When#adding#a#frontGrunner,#the#following#helper#functions#must#be#edited#to# indicate#which#frontGrunner#servers#are#paired#with#each#other,#which#exchanges# they#monitor#and#the#delay#agents#associated#with#them:# # -- returns (otherfrid, myexchid, otherexchangeid) fr_findids :: Int -> (Int,Int,Int) fr_findids frid | frid == fr1id = (fr2id, fr1exchid, fr2exchid) | frid == fr2id = (fr1id, fr2exchid, fr1exchid) | frid == fr3id = (fr4id, fr1exchid, fr2exchid) | frid == fr4id = (fr3id, fr2exchid, fr1exchid) | otherwise = error ("findotherexch: Not valid id to find other exchange")

-- delay from other front runner to this front runner, and delay from local exchange -- to this front runner, to receive both exchange's trade data and orderlists fr_getmydelayids frid | frid == fr1id = (fr2tofr1delayid,exch1tofr1delayid) | frid == fr2id = (fr1tofr2delayid,exch2tofr2delayid) | frid == fr3id = (fr4tofr3delayid,exch1tofr3delayid) | frid == fr4id = (fr3tofr4delayid,exch2tofr4delayid) | otherwise = error ("fr_getmydelayids: Not valid frid")

-- delay from frontrunner to local exchange fr_getexchdelayid frid | frid == fr1id = fr1toexch1delayid | frid == fr2id = fr2toexch2delayid | frid == fr3id = fr3toexch1delayid | frid == fr4id = fr4toexch2delayid | otherwise = error ("fr_getexchdelayid: Not a valid frid")# #

85# When#adding#a#broker,#the#following#helper#functions#must#be#edited#to#indicate# which#exchanges#they#send#orders#to#and#the#delays#associated#with#them.# # -- delay from exchanges to this broker broker_getmydelayids brokerid | brokerid == broker1id = (exch1tobroker1delayid,exch2tobroker1delayid) | brokerid == broker2id = (exch1tobroker2delayid,exch2tobroker2delayid) | otherwise = error "broker_getmydelayids: brokerid not recognised"

-- delay from broker to each exchange broker_getexchdelayids brokerid | brokerid == broker1id = (broker1toexch1delayid,broker1toexch2delayid) | brokerid == broker2id = (broker2toexch1delayid,broker2toexch2delayid) | otherwise = error "broker_getexchdelayids: brokerid not recognised"# # #

86# 8.4. System(Manual(

8.4.1. Creating(a(New(Experiment( # The#TestHarness.hs#module#is#full#of#functions,#each#of#which#is#a#different# experiment.#The#frontGrunning#experiment#used#for#this#project#is#listed#at#the# bottom#of#the#test#harness:# # testfrontrunning :: IO () testfrontrunning = do createDirectoryIfMissing True ("tracefiles/"++thefilename) sim 100 meinargs meinagents where meinargs = [(Arg (Str "Calm", 1)), (Arg (Str "Randomise", 1)), (Arg (Str fthefilename, 9989793425))] fthefilename = "tracefiles/" ++ thefilename ++ "/" ++ thefilename thefilename = "Frontrunning" meinagents = delays ++ exchanges ++ frontrunners ++ brokers ++ traders delays = (rep (length delay_list) (delaywrapper, [0..broadcast_channels])) exchanges = (rep (length exchange_list) (nice_mime_wrapper, [0..broadcast_channels])) traders = [(mytraderwrapper, [0..broadcast_channels])] brokers = (rep (length broker_list) (brokerwrapper, [0..broadcast_channels])) frontrunners = (rep (length frontrunner_list) (frwrapper, [0..broadcast_channels]))# # Each#experiment#creates#a#directory#for#the#trace#files##before#calling#the#‘sim’# function#from#Sim.hs,#which#takes#the#number#of#timesteps#the#experiment# should#be#run#for,#a#list#of#global#arguments#that#is#passed#down#to#each#agent#in# the#experiment,#and#the#list#of#agents.# # These#agents#are#specified#below#in#the#‘where’#block,#and#each#repeats#the#same# wrapper#function#for#each#agent,#depending#on#the#size#of#the#lists#in#Agent.hs.# The#agents#themselves#then#use#the#helper#functions#and#lookup#lists#in#Agent.hs# to#find#their#specific#parameters#within#the#experiment#setup,#as#shown#in#the# user#manual#in#Section#8.3.# # The#first#two#global#arguments#used#in#this#experiment#are#used#by#the#exchange# agents,#but#are#largely#irrelevant#for#this#particular#frontGrunning#experiment# and#apply#to#experiments#that#involve#marketGmaking#HFTs#from#previous# experiments.#The#third#argument#is#used#by#the#simulator,#to#uniquely#identify# the#trace#file#when#writing#to#it.# #

8.4.2. Creating(a(New(Agent( # A#new#agent#would#require#a#new#module#following#the#general#structure#below,# with#a#wrapper#function#and#logic#function.# # fundlogic inventory myid ti inrands ingausses uv buyer sig = if buyer == True then order_create price actualsize ti sig (Bid Goodtillcancelled) else order_create price actualsize ti sig (Offer Goodtillcancelled)

fundwrapper :: Agent_t fundwrapper (Emptyagentstate) args any myid = fundwrapper (Newagstate ([0], [], 0, (map (order_setuid "fundwrapper") [0..]),[], [])) args any myid

fundwrapper (Newagstate ([invent], oldorders, sent, uids, rnds, any)) args ((ti, messages, broadcasts) : simstateinfos) myid = [msgg] : (fundwrapper (Newagstate ([newinvent], oldorders, sent, remaininguids, (drop 15 rnds), any)) args simstateinfos myid) where (msgg) = (ordermessage (myid, 1) (head forders)) (remaininguids, forders) = applyuids uids [ordr]

87# newinvent = foldr (+) invent (map getmovement mytrades) where mytrades = map (cpsafehd "fundwrapper1") (filter (not.null) (map msg_gettrade messages)) getmovement o |(isBuySide o) = (order_getsize o) |(isSellSide o) = (- (order_getsize o)) |otherwise = error "fundwrapper - getmovement - order type not recognised." ordr = fundlogic invent myid ti rnds (gaussians) underlyingvalue buyer mytraderid # # The#first#wrapper#function#initialises#the#agent’s#state,#which#can#be#different#for# each#agent#depending#on#the#values#it#needs#to#carry#through#to#the#next#timeG step.#These#states#and#their#values#can#be#edited#in#the#Comm.hs#(common)# module.#The#main#wrapper#function#returns#a#recursive#call#to#itself#that#is# appended#to#a#list#of#messages#it#produces,#to#be#handled#and#delivered#by#the# simulator.#Each#recursive#call#represents#one#timeGstep.# # The#list#of#messages#can#be#of#any#type,#and#in#the#example#above#the#agent# produces#order#messages#specified#by#the#logic#function.#These#orders#then#have# unique#ids#applied#to#them,#before#being#wrapped#in#an#order#message.#The# order#message’s#‘from#id’#is#the#id#for#this#agent,#allocated#by#the#simulator#via# the#parameter#‘myid’,#and#the#‘to#id’#of#the#message#is#1,#which#could#be#an# exchange#with#id#1.# # The#‘newinvent’#variable#is#also#being#updated#and#carried#in#the#agent’s#state.# To#update#it,#the#agent#is#mapping#over#the#list#of#incoming#messages,#checking# for#trade#confirmation#messages.#It#is#then#aggregating#the#order#sizes,# depending#on#whether#they#are#‘buy’#or#‘sell’#trade#confirmations#to#get#a#net# inventory#number#for#this#agent,#i.e.#how#much#stock#it#currently#has.# # These#are#examples#of#the#type#of#activity#that#an#agent#would#do#in#an# experiment.#Other#existing#modules,#such#as#the#exchanges,#can#be#used#to#see# how#more#complex#functions#are#performed.#Note#that#any#new#modules#created# must#be#added#to#the#makefile#for#it#to#include#it#during#compilation.

88# 8.5. Testing(and(Relevant(Results(

8.5.1. Testing(

8.5.1.1. Heap*Profile*Snippet*

89# 8.5.1.2. Trace*File*Snippet* # This#is#a#trace#file#snippet#from#an#experiment#with#2#brokers#and#1#frontGrunner.# At#timeGstep#16#(stated#as#‘System#Time:#16’#here),#broker#1#with#id#19#sends# ‘BuyAndKill’#market#order#messages#out#to#the#delay#agents#for#exchange#1#and# 2,#with#ids#5#and#6,#respectively.# # At#timestep#19#the#‘broker#1#to#exchange#2’#delay#agent#forwards#the#order# message#onto#exchange#2,#with#id#16.# # At#timestep#20,#broker#2#with#id#20#sends#‘BuyAndKill’#market#order#messages# out#to#the#delay#agents#for#exchange#1#and#2,#with#ids#11#and#12,#respectively.#In# the#same#timestep,#broker#1’s#market#order#is#executed#at#exchange#2#and# matches#with#an#existing#offer.#The#new#orderlist#and#trade#data#are#now#being# broadcast.### # System#Time:#15# Messages#to#sim:#Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=,## # Broadcasts:## Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer#

90# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]]]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[([],Bids)]# # # END#OF#STATE# # ======# ,## # System#Time:#16# Messages#to#sim:## Message#from/to#(19,5)#(uid:#30,#$0.1,#50.0#shares,#at#(15,G1)#secs,##from#HFT#19,#of#type#Buy#Andkill)# ###### Message#from/to#(19,6)#(uid:#31,#$0.1,#50.0#shares,#at#(15,G1)#secs,##from#HFT#19,#of#type#Buy#Andkill)# ###### +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message,## # Broadcasts:## Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]]]# Broadcast#from/to#group#(16,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[([],Bids)]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer#

91# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# # # END#OF#STATE# # ======# ,## # System#Time:#17# Messages#to#sim:#Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=,## # # Broadcasts:## Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(16,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]]]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer#

92# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# # # END#OF#STATE# # ======# ,## # System#Time:#18# Messages#to#sim:## +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message,## # Broadcasts:## Broadcast#from/to#group#(13,14)#[([],Bids)]# Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(13,14)#[([],Asks)]# Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]]]# Broadcast#from/to#group#(16,15)#[([],Bids)]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# #

93# # END#OF#STATE# # ======# ,## # System#Time:#19# Messages#to#sim:## +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# Message#from/to#(6,16)#(uid:#31,#$0.1,#50.0#shares,#at#(15,G1)#secs,##from#HFT#19,#of#type#Buy#Andkill)# #####,## # Broadcasts:## Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(13,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(13,14)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,0.0,2000.0]]]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]#

94# # # END#OF#STATE# # ======# ,## # System#Time:#20# Messages#to#sim:## Message#from/to#(20,11)#(uid:#38,#$0.1,#50.0#shares,#at#(19,G1)#secs,##from#HFT#20,#of#type#Buy#Andkill)# ###### Message#from/to#(20,12)#(uid:#39,#$0.1,#50.0#shares,#at#(19,G1)#secs,##from#HFT#20,#of#type#Buy#Andkill)# #####Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(15,14)# Numlistbroadcast#[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=Data#message# +=+=+=+=+=+=+=+=+=+=+=+=+=# Debug#message:(16,15)# Numlistbroadcast#[0.0,1999.0,0.0,250.0,0.0,5.0,0.0,250.0,1.0,2000.0]# +=+=+=+=+=+=+=+=+=+=+=+=+=# ======# # To:#19# Order:## (1999.0,50.0,(15,0),HFT#19,Buy#Andkill,31)# # #matched#with# # Order:(1999.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,4)# # ======# Ackmessage(16G>19):#The#following#order#was#successful:## (0.1,0.0,(15,0),HFT#19,Buy#Andkill,31)# ======# # To:#21# Order:## (1999.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,4)# # #matched#with# # Order:(1999.0,50.0,(15,0),HFT#19,Buy#Andkill,31)# # ======,## # Broadcasts:## Broadcast#from/to#group#(3,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(15,14)#[LOBbcast#contents:#[[0.0,1998.0,0.0,200.0,0.0,4.0,0.0,200.0,0.0,2000.0]]]# Broadcast#from/to#group#(13,14)#[([],Bids)]# Broadcast#from/to#group#(3,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(13,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]# Broadcast#from/to#group#(7,14)#[([(1998.0,[(1998.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,0)]),(2000.0,[(2000.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,1)]),(2002.0,[(2002.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,2)]),(2004.0,[(2004.0,50.0,(0,3),HFT#21,Offer#Goodtillcancelled,3)])],Asks)]#

95# Broadcast#from/to#group#(7,14)#[([],Bids)]# Broadcast#from/to#group#(15,14)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[TRADE#DATA:#(1999.0,50.0)#END#OF#TRADE]# Broadcast#from/to#group#(4,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(16,15)#[LOBbcast#contents:#[[0.0,2001.0,0.0,200.0,0.0,4.0,0.0,200.0,1.0,1999.0]]]# Broadcast#from/to#group#(14,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(8,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[([],Bids)]# Broadcast#from/to#group#(16,15)#[([(1999.0,[]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# Broadcast#from/to#group#(14,15)#[([],Bids)]# Broadcast#from/to#group#(4,15)#[([],Bids)]# Broadcast#from/to#group#(8,15)#[([(1999.0,[(1999.0,50.0,(0,3),HFT#21,Offer# Goodtillcancelled,4)]),(2001.0,[(2001.0,50.0,(0,0),HFT#21,Offer# Goodtillcancelled,5)]),(2003.0,[(2003.0,50.0,(0,1),HFT#21,Offer# Goodtillcancelled,6)]),(2005.0,[(2005.0,50.0,(0,2),HFT#21,Offer# Goodtillcancelled,7)]),(2007.0,[(2007.0,50.0,(0,4),HFT#21,Offer#Goodtillcancelled,8)])],Asks)]# # # END#OF#STATE# ======# #

96# 8.5.2. Referenced(Results(

8.5.2.1. OrderIList*Setup*Configurations* # Initial'Exchange'Order1Lists'–'Setup'1' '

# # Initial'Exchange'Order1Lists'–'Setup'2' #

# #

8.5.2.2. Minimal*Setup* # Front1Runner'Profits'with'Setup'2' # #

# #

97# 8.5.2.3. Multiple*Brokers*

8.5.2.3.1. Targeting/One/Broker/ # Only#calculating#alpha#and#beta#values#for#broker#1,#even#though#there#were#two# brokers:# # Front1Runner'Profits'with'Setup'1' #

# # Showing#that#the#algorithm#produces#the#same#result#with#a#random#initial# orderGlist#for#each#exchange:# # Front1Runner'Profits'with'Setup'2' #

# #

8.5.2.3.2. /Identifying/Broker/ # Calculating#alpha#and#beta#values#for#both#brokers,#and#then#using#the#values#to# identify#the#broker#that#send#the#order#and#frontGrunning#it#accordingly:# # Front1Runner'Profits'with'Setup'1' #

# # # #

98# 8.5.2.3.3. Brokers’/first/orders/sent/to/different/exchanges/ # 'Front1Runner'Profits'with'Setup'1'

# # Showing#that#the#algorithm#produces#the#same#result#with#a#random#initial# orderGlist#for#each#exchange:# # Front1Runner'Profits'with'Setup'2' #

# Increasing*delays*between*exchanges*and*front5runners*by*1:* * Front1Runner'Profits'with'Setup'2' #

# # # # # # # #

99# 8.5.2.4. Multiple*FrontIrunners*

8.5.2.4.1. Front?Runners/Closer/to/the/Same/Exchange/ # Front1Runner'Profits'with'Setup'2' #

# #

8.5.2.4.2. Front?runners/Closer/to/Different/Exchanges/ # Front1Runner'Profits'with'Setup'2' #

# #

8.5.2.5. *Multiple*Brokers*and*FrontIRunners* # Front1Runner'Profits'with'Setup'2' #

# #

100# 8.6. Project(Plan( ' Student’s'name:''' Aman#Chopra# Supervisor’s'name:## Dr.#Christopher#D.#Clack# ' Project'Title:##Modelling#FrontGRunning#in#High#Frequency#Trading# ' Aim:'To#discover#and#gain#an#understanding#of#the#realGworld# situations#that#may#arise#where#high#frequency#traders#make#a#loss# when#frontGrunning.# # Objectives:'' ' 1. Create#mechanisms#to#allow#the#existing#simulator#to#create#an# example#of#front#running,#including#multiple#exchanges#and# delays#in#the#messages#sent#between#the#exchanges#and#the# agents.# 2. Recreate#a#frontGrunning#example#with#high#frequency#traders.# 3. Run#experiments#on#the#simulator,#using#random#data#to# simulate#as#many#realGworld#scenarios#as#possible.# 4. Analyse#the#data#and#pinpoint#occasions#where#the#high# frequency#traders#have#not#made#a#profit#when#front#running.# 5. Establish#preGrequisites#for#situations#like#these#to#take#place,# or#for#the#system#to#become#unstable.# # Deliverables' # G Models#that#outline#the#key#requirements#needed#to#create#a# scenario#where#frontGrunning#high#frequency#traders#make#a# loss.# G The#relevant#parts#of#the#obtained#data#produced#by#the# simulation#that#show#the#highGfrequency#traders#making#a#loss# G The#code#written#in#Haskell#that#produced#the#simulations#and# the#range#of#parameters#that#have#been#used#to#run#them# # # ' ' ' ' '

101# ' Work'plan:'' ' •'Project#start#to#end#October#(4#weeks)#Problem#definition,#research,# reading#and#review.# # G Decide#on#a#suitable#project#title#and#outline#objectives# G Discuss#the#aims#of#the#project#with#supervisor# G Reading#and#research#into#the#subject#(Flash#Boys#by#Michael# Lewis)# # •#MidGOctober#to#midGNovember#(4#weeks)#Simulator#testing#and# familiarisation.# # G Explore#existing#simulator#codebase# G Run#example#tests## # •#MidGNovember#to#early#December#(3#weeks)#System#design,#coding# small#test#programs#and#simple#prototypes.# # G Ensure#mechanisms#for#multiple#exchanges,#brokers,#highG frequency#traders#and#delayed#messages,#etc.#are#working#as# needed.## G Note#what#needs#to#be#implemented#to#run#frontGrunning#tests.# # •#Early#December#to#lateGJanuary#(6#weeks)#System#implementation.# # G Implement#remaining#mechanisms#to#create#different#scenarios# with# # •#End#of#January#(1#week)#Interim#Report.# # •#February#(4#weeks)#System#testing#and#data#analysis.# # G Run#tests#with#multiple#setups#and#analyse#data# G Detect#scenarios#where#highGfrequency#traders#have#made#a# loss# G Model#scenarios,#stating#preGrequisites# G Test#minimal#cases#to#ensure#models#are#correct,#and#that#all# preGrequisites#are#needed### # •#March#(4#weeks)#Work#on#Final#Report.#

102#