[{"content":"Retroedge is a Rust-based trading simulator.\nYou can experiment with the interactive app directly on the live website:\nhttps://retroedge.io or read the blog series to gain more context:\nPart 1 — Motivation \u0026amp; System Architecture Part 2 — Application Architecture Part 3 — Application Logic ","date":"15 December 2025","externalUrl":null,"permalink":"/projects/retroedge/","section":"Projects","summary":"A Rust-based trading simulator","title":"Retroedge","type":"projects"},{"content":"If you\u0026rsquo;ve ever wondered how a betting exchange works and how to build a simplified version of one, this blog series will help you achieve that:\nPart 1 — Motivation \u0026amp; System Architecture Part 2 — Inside the Order Matching Engine Part 3 — Inside the Order Book Part 4 — Inside the Event Streaming Pipeline Part 5 — Inside the Consumer Pipeline The series is a mixture of system diagrams, prose, and code. By the time you\u0026rsquo;ve gone through it, you should be able to have a functioning system that can:\ningest order-related events match them according to a matching policy emit trade events to an event log push trade events from the event log to downstram consumer services (analytics, persistence, etc.) ","date":"1 June 2026","externalUrl":null,"permalink":"/projects/betting_exchange/","section":"Projects","summary":"A Rust \u0026amp; Python event-driven betting exchange prototype","title":"Betting Exchange","type":"projects"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/asynchronous-programming/","section":"Tags","summary":"","title":"Asynchronous Programming","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/series/betting-exchange/","section":"Series","summary":"","title":"Betting Exchange","type":"series"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/betting-exchange/","section":"Tags","summary":"","title":"Betting Exchange","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/event-driven-architecture/","section":"Tags","summary":"","title":"Event-Driven Architecture","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/message-queue/","section":"Tags","summary":"","title":"Message Queue","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/order-matching-engine/","section":"Tags","summary":"","title":"Order Matching Engine","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/order-matching-system/","section":"Tags","summary":"","title":"Order Matching System","type":"tags"},{"content":"In the previous article we followed trade events as they left the matching engine and were appended to a Redis Stream. Publishing an event, however, is only half of the story. Events become useful when external services consume them and perform work in response.\nIn this article we will examine the consumer side of the architecture.\nFrom Event Stream to Consumer # Visually:\nflowchart TD RS[Redis Stream] EC[\"External Consumers\"] CA[Consumer A] CB[Consumer B] CC[Consumer C] RS --\u003e EC EC --\u003e CA EC --\u003e CB EC --\u003e CC Notice that producer part of the architecture has been omitted. That is intentional and the goal is to highlight how consumers are decoupled from producers. Both layers in the architecture don\u0026rsquo;t know about each other. The link between the two parts is Redis, which acts as the intermediary.\nConsumers communicate only with Redis and read events from it, not directly from the producer.\nAt this level of the system, Redis is the only shared dependency between all components.\nIndependent Consumption with Consumer Groups # In this system, a consumer is a long-running process that reads trade events from Redis and performs some form of downstream work. Multiple consumers can exist at the same time, but they remain independent processes and communicate only through Redis.\nWhen scaling this pattern, Redis Consumer Groups allow multiple independent consumption streams over the same event log. Each group maintains its own read position, meaning different downstream systems can process the same events without interfering with each other.\nVisually:\nflowchart TD RS[Redis Stream] CA[Consumer A] GA[Group A] CB[Consumer B] GB[Group B] RS --\u003e GA --\u003e CA RS --\u003e GB --\u003e CB Consumer Responsibilities # Once trade events are available in the stream, consumers are free to interpret them according to their own domain responsibilities. A consumer might:\npersist trades (or other events) compute analytics publish notifications update dashboards feed Machine Learning systems Consumer Implementation (Python) # The definition of the consumer is:\n# consumer.py import redis.asyncio as redis import json from process import process_event async def redis_consumer(): \u0026#34;\u0026#34;\u0026#34; Reads a stream from Redis via XREAD from a consumer group, aka XREADGROUP. :return: \u0026#34;\u0026#34;\u0026#34; STREAM = \u0026#34;events_stream\u0026#34; GROUP = \u0026#34;analytics_group\u0026#34; CONSUMER = \u0026#34;analytics_worker\u0026#34; r = redis.Redis( host=\u0026#34;localhost\u0026#34;, port=6379, decode_responses=True, socket_timeout=None ) last_id = \u0026#34;\u0026gt;\u0026#34; # create group, if it doesn\u0026#39;t exist try: await r.xgroup_create(STREAM, GROUP, id=\u0026#34;$\u0026#34;, mkstream=True) except redis.ResponseError as err: if \u0026#34;BUSYGROUP\u0026#34; not in str(err): raise while True: messages = await r.xreadgroup( groupname=GROUP, consumername=CONSUMER, streams={STREAM: last_id}, count=50, block=0 ) if not messages: continue for _, entries, in messages: for message_id, fields in entries: event = json.loads(fields[\u0026#34;event\u0026#34;]) await process_event(event) await r.xack(STREAM, GROUP, message_id) The key part lives inside the while True block. The consumer runs indefinitely as part of the analytics_group consumer group. As new trade events arrive in the stream, Redis delivers them to the consumer, which processes the event and acknowledges successful handling via XACK command.\nThe \u0026gt; character is a stream identifier that instructs Redis to deliver only new messages that have not been seen by the consumer group. This allows consumers to continuously process newly generated trade events without manually tracking stream offsets.\nFor the sake of completion, the definition of process_event is:\nasync def process_event(event): print(\u0026#34;\\n*** Analytics happenings ***\\n\u0026#34;) print(f\u0026#34;=== Trade information === \\n\u0026#34;) print(f\u0026#34;Trade id: {event[\u0026#34;trade_id\u0026#34;]}\u0026#34;) print(f\u0026#34;Market id: {event[\u0026#34;market_id\u0026#34;]}\u0026#34;) print(f\u0026#34;Odds: {event[\u0026#34;odds\u0026#34;][\u0026#34;ticks\u0026#34;]}\u0026#34;) print(f\u0026#34;Stake: {event[\u0026#34;stake\u0026#34;][\u0026#34;value\u0026#34;]}\u0026#34;) print(f\u0026#34;Timestamp: {event[\u0026#34;timestamp\u0026#34;]}\u0026#34;) Why a separate process? # Separation of concerns # Matching engine matches orders (producer).\nConsumers react to events (consumers).\nFailure isolation # Consumer crashes do not affect the producer, so the engine can keep matching.\nConsumer groups also isolate downstream services from one another by maintaining independent read positions.\nLanguage independence # Consumers can be written in any language.\nScalability # Consumers can evolve independently.\nDesign decisions # Event-driven architecture # The system is organised around events rather than direct service-to-service calls. Producers publish trade events once, and consumers decide independently how to react to them.\nLoose coupling # The matching engine has no knowledge of downstream consumers, while consumers have no knowledge of how events were produced. Redis acts as the intermediary between the two layers.\nIndependent deployment # Consumers can be developed, deployed, and modified independently of the matching engine. New consumers can be introduced without changing producer code.\nReplayability # Because events are stored in Redis Streams, newly introduced consumers can process historical events rather than only future ones, subject to stream retention policy. This is a useful property when introducing new consumer services.\nLimitations and future work # The consumer implemented here is intentionally simplified and merely logs received events. Real systems would likely persist data, compute analytics, expose APIs, or publish websocket updates back to clients.\nAt this point the end-to-end architecture is complete. Orders enter the matching engine, trades are generated deterministically, events are streamed through Redis, and independent consumers react to those events without affecting the matching path.\nTogether, these components form a simple event-driven exchange architecture that cleanly separates matching, event distribution, and downstream processing.\n","date":"3 June 2026","externalUrl":null,"permalink":"/projects/rust_betting_exchange_5/","section":"Projects","summary":"","title":"Part V — Inside the Consumer Pipeline","type":"projects"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/prediction-markets/","section":"Tags","summary":"","title":"Prediction Markets","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/projects/","section":"Projects","summary":"","title":"Projects","type":"projects"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/redis/","section":"Tags","summary":"","title":"Redis","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/rust/","section":"Tags","summary":"","title":"Rust","type":"tags"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"3 June 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":" In the previous article we examined how the order book structures and organises incoming orders, enabling the matching engine to deterministically produce trades. However, producing a trade is only one part of the system. Once a trade is generated by the matching engine, it becomes an externalised event that must be propagated beyond the in-memory state of the engine.\nRecall the main system diagram from part I. In this article we will cover what happens after a trade has been emitted from the engine.\nThe following diagram shows the full path of a trade event, from generation inside the matching engine to consumption by external systems:\nflowchart TD OB[\"Insert order in order book (not of interest here)\"] E{Engine} EC[\"External Consumers\"] AL[Analytics Layer] PL[Persistence Layer] RS[Redis Stream] E --\u003e|No| OB E --\u003e|Yes| J[Emit Trade Event] J --\u003e BCT[Background Consumer Thread: Receive Trade Event] BCT --\u003e EP[Event Publisher: publish event to Redis Stream] EP --\u003e RS RS --\u003e EC EC --\u003e AL EC --\u003e PL The key boundary in this system is the point where the matching engine emits a Trade event. From this moment onward, the engine is no longer responsible for what happens to the data. Its only role is to guarantee that the event is produced deterministically.\nThis boundary is implemented using an asynchronous multi-producer, single-consumer (MPSC) channel. In this context, the engine will be the producer and another component will be the single consumer. That component will be a long-running background worker.\nThis background worker receives these events and acts as a bridge between the Rust runtime and external systems. Its responsibility is to forward each Trade event to an external event stream (Redis Streams in this prototype).\nEvent Consumer Implementation # The event consumer worker runs as a long-lived asynchronous task. It continuously receives Trade events from the matching engine and forwards them to Redis.\nThe worker definition is:\nuse deadpool_redis::{Pool as RedisPool}; use tokio::sync::mpsc::{Receiver as TokioReceiver}; use crate::domain::trade::Trade; pub async fn evt_consumer_worker(mut receiver: TokioReceiver\u0026lt;Trade\u0026gt;, redis_pool: \u0026amp;RedisPool) { let mut connection = create_redis_connection(redis_pool).await .expect(\u0026#34;Failed to create Redis connection\u0026#34;); while let Some(event) = receiver.recv().await { write_to_redis(\u0026amp;mut connection, event).await .expect(\u0026#34;Failed to stream event to Redis\u0026#34;); }; } The worker continuously listens on the MPSC receiver. Each incoming Trade event is processed sequentially and forwarded to Redis.\nThe function responsible for publishing events to Redis is:\nuse deadpool_redis::{Connection}; use redis::RedisResult; use crate::domain::trade::Trade; pub async fn write_to_redis(connection: \u0026amp;mut Connection, event: Trade) -\u0026gt; RedisResult\u0026lt;()\u0026gt; { let evt = serde_json::to_string(\u0026amp;event).unwrap(); let result = redis::cmd(\u0026#34;XADD\u0026#34;) .arg(\u0026#34;events_stream\u0026#34;) .arg(\u0026#34;*\u0026#34;) .arg(\u0026#34;event\u0026#34;) .arg(evt) .query_async(connection) .await?; println!(\u0026#34;[redis] pushed event\u0026#34;); result } Each event is serialised and appended using the XADD command.\nSupporting code for connection management and pool creation has been omitted for brevity. The important architectural detail is that the worker maintains a Redis connection and continuously forwards Trade events from the MPSC channel to a Redis Stream.\nThis design introduces a clear separation between deterministic computation and external side effects.\nDesign decisions # Engine does not perform I/O # The matching engine is deliberately isolated from any external side effects. Its only responsibility is to generate deterministic Trade events.\nAsynchronous boundary via MPSC channel # Trade events are passed out of the engine using a \\( Tokio \\) MPSC channel. The engine acts as the producer, while a single background worker consumes events asynchronously.\nNon-blocking event emission (try_send) # Event emission uses try_send rather than a blocking .send(). This ensures the matching engine remains responsive and is not stalled by downstream latency or backpressure from the consumer pipeline.\nSingle consumer design # The system uses a single consumer to maintain ordering guarantees for Trade events. This simplifies consistency at the cost of horizontal scalability.\nRedis Streams as event log # Redis Streams is treated as an external event sink rather than part of the matching system. It provides an append-only log of trade activity for downstream services.\nThis completes the journey from order submission to external event propagation. We have now seen how a deterministic in-memory matching engine produces trades and how those trades are streamed out of the system for downstream processing.\nIn the next article we will move beyond the matching engine and explore how downstream services consume trade events from Redis Streams.\n","date":"3 June 2026","externalUrl":null,"permalink":"/projects/rust_betting_exchange_4/","section":"Projects","summary":"","title":"Part IV — Inside the Event Stream Pipeline","type":"projects"},{"content":" In the previous article we covered the order matching engine, its structure, purpose, behaviour, and how it uses the order book to manage and match orders. In this article we will examine the internals of the order book and how its design enables deterministic behaviour in the order matching engine (OME).\nAn order book, in the context of a betting exchange, is a collection of unmatched orders representing participants\u0026rsquo; interest in a given market. For example:\nMarket: Team A vs Team B Outcome: Team A wins Order Book (Back vs Lay): ------------------------------------------------------------ BACK SIDE | LAY SIDE ------------------------------------------------------------ Odds | Liquidity | Odds | Liquidity ------------------------------------------------------------ 2.06 | £300 | 2.10 | £400 2.10 | £500 | 2.14 | £600 2.08 | £200 | 2.16 | £250 ------------------------------------------------------------ In the previous article we covered how matching works, so we know that, with the current implementation, the BACK at 2.10 will be matched with the LAY at 2.10. The question now becomes: how does the order book organise orders so that the matching engine can find the correct counterpart quickly while preserving First In, First Out (FIFO) ordering?\nAnatomy of the Order Book # Before looking at the implementation details, it\u0026rsquo;s worth considering what the order book needs to achieve.\nAt a minimum, it must:\ngroup orders by odds level; preserve FIFO ordering within each level; support efficient insertion of new orders; support efficient lookup of existing levels; support removal of fully matched orders. These requirements heavily influence the choice of data structures. Rather than maintaining a single collection of orders and searching through it on every match attempt, the order book organises orders into price-level buckets.\nOrderBook ├── BACKS │ ├── 2.06 -\u0026gt; [order, order, order] │ ├── 2.08 -\u0026gt; [order] │ └── 2.10 -\u0026gt; [order, order] │ └── LAYS ├── 2.10 -\u0026gt; [order] ├── 2.14 -\u0026gt; [order, order] └── 2.16 -\u0026gt; [order] Each side of the book is organised independently. Orders are first grouped by odds level and then queued according to arrival time.\nThis structure allows the matching engine to locate a specific odds level directly and process orders in FIFO order without scanning the entire book.\nImplementation Details # In code, the structure is represented as two maps: one for BACK orders and another for LAY orders. Each map stores a queue of orders for a given odds level.\nIn pseudo-code:\nOrderBook ├── BACKS: map\u0026lt;odds, queue\u0026lt;order\u0026gt;\u0026gt; └── LAYS: map\u0026lt;odds, queue\u0026lt;order\u0026gt;\u0026gt; The next step is representing this structure in memory.\nEnter the \\( BTreeMap\\) # Rust offers several map implementations, with HashMap and BTreeMap being the most commonly used. At first glance, HashMap may seem like the obvious choice because it provides average-case \\( O(1) \\) lookups. However, lookup speed is not the only consideration when designing an order book.\nSo why the BTreeMap? It offers:\nOrdered price levels # A BTreeMap maintains keys in sorted order. This means price levels are always stored from lowest to highest odds without requiring additional sorting. This becomes particularly useful in a production-style matching engine where finding the best available price is a common operation.\nThe natural ordering of keys is a property of the underlying \\( B-tree \\) data structure, which stores keys in sorted order while maintaining logarithmic lookup performance.\nDeterministic iteration # Unlike HashMap, iteration order in a BTreeMap is deterministic. This aligns well with the broader design goal of keeping the matching engine deterministic and predictable in all environments: development, testing, and production.\nFuture-proofing # Although this prototype currently matches only exact odds levels, future versions may implement full price-time priority. In that model, locating the best available price becomes a first-class operation.\nA sorted structure naturally supports that evolution.\nLimitations and trade-offs # The trade-off is lookup complexity. Hashmap provides average-case \\( O(1) \\) access, while a BTreeMap does it in \\( O(log \\ n) \\). For this prototype, the benefits of ordered price levels and deterministic iteration outweighed the additional lookup cost.\nWith the design motivations established, we can now examine the implementation.\nCode # use std::collections::{BTreeMap, VecDeque}; pub struct OrderBook { pub market: Market, pub backs: BTreeMap\u0026lt;Odds, VecDeque\u0026lt;Order\u0026gt;\u0026gt;, pub lays: BTreeMap\u0026lt;Odds, VecDeque\u0026lt;Order\u0026gt;\u0026gt; } The BTreeMap groups orders by Odds levels, while the VecDeque preserves FIFO ordering within each level. Combined, they organise orders along two dimensions: price and time.\nFor the sake of completion here\u0026rsquo;s the code for Odds and Order:\npub struct Odds { pub ticks: u64, } pub struct Order { pub order_id: Uuid, pub market_id: Uuid, pub side: OrderSide, kind: OrderKind, pub odds: Odds, stake: Stake, pub remaining_stake: Stake, status: OrderStatus, timestamp: DateTime\u0026lt;Utc\u0026gt;, } So far we have examined the order book as the structure that organises orders for deterministic matching. In the next article we will look at how trade events produced by the matching engine are streamed out of the system.\n","date":"2 June 2026","externalUrl":null,"permalink":"/projects/rust_betting_exchange_3/","section":"Projects","summary":"","title":"Part III — Inside the Order Book","type":"projects"},{"content":" In the previous article we covered, at a high-level the architecture of this prototype betting exchange, its design decisions and trade-offs. In this article we will cover arguably the most interesting part of the system: the order matching engine (OME), which is part of the Order Matching System (OMS).\nAn OME is, in essence, an electronic system that matches buy and sell orders in a market. The market could be:\nequities commodities cryptocurrencies futures (derivatives) betting Each market will have its own unique set of participants, tradeable instruments, and rules, and as such when building an OME and the supporting OMS around it, domain-specific knowledge and assumptions are required.\nCentral to any OME is the matching policy, which governs how orders are meant to be matched.\nMatching Policy # This policy, just like the wider OME is driven by the specific domain. However, due to the similarity of incentives across market participants, a small number of matching algorithms have emerged as dominant, with the most common being: price-time priority, which is a combination of the following rules:\nthe best price wins if price is equal, the earliest order wins This prototype only implements the second rule. Orders are matched at exact odds levels, and FIFO ordering is preserved within each level.\nFor example:\nBID/BACK ASK/LAY 10.5 @ 100 10.5 @ 100 will match, but:\nBID/BACK ASK/LAY 10.6 @ 100 10.5 @ 100 10.4 @ 100 will not. In a real-world implementation, with best-price the bid would be matched with the 10.4 ask because it is economically beneficial for both traders. To generalise, a trade happens when:\n$$ highest \\ bid \\geq lowest \\ ask $$ Betting exchange focus # Earlier I mentioned that domain-specific knowledge is required to build an OME that is suitable for the target markets. In this series I\u0026rsquo;ll focus on betting exchanges as an alternative to traditional financial markets. As such, the code incorporates betting terminology, so you\u0026rsquo;ll see BACK instead of BID and LAY in place of ASK. They are similar but not the same.\nIn a betting exchange, unlike a traditional market, you\u0026rsquo;re not trading on an outcome that involves the exchange of a physical commodity like oil futures with delivery, or the exchange of an instrument like a company stock, etc. but on a single event with multiple outcomes. For example three people can bet on the outcome of a football match, one person believes team A will win, another thinks team A will lose, and another thinks it\u0026rsquo;ll be a draw.\nThat is the crucial distinction between trading an asset and betting on an outcome.\nTo draw an analogy from public equities, consider a company\u0026rsquo;s upcoming earnings call. Rather than trading the stock itself, participants could speculate on one of several outcomes:\nCompany X earning call (due a week from now) Outcomes of X\u0026#39;s earnings: - exceeds analyst\u0026#39;s expectations (equivalent to win in the football match) - just about meets the expectations (draw) - fails to meet expectations (lose) Participants express views on any of these three outcomes. The likelihood of any outcome will be reflected in the odds. This pattern is consistent across all prediction markets. With likelier outcomes having lower odds and lower payouts, and less likely outcomes having higher odds and payouts.\nWith the above context we can now dive into the engine\u0026rsquo;s architecture.\nEngine Architecture # Scope # This engine is responsible for maintaining an in-memory order book and matching incoming orders using deterministic rules.\nIt is deliberately scoped to a single market. Each market owns its own order book and matching engine instance. This avoids cross-market coordination inside the matching path and keeps the implementation straightforward.\nSo:\n1 market -\u0026gt; 1 order book -\u0026gt; 1 matching engine rather than:\nmany markets -\u0026gt; shared matching engine System Diagram # flowchart TD A[Incoming Order] --\u003e B[Validate Order] B --\u003e C[Select Opposite Side of Order Book] C --\u003e D{Find Matching Price Level} D --\u003e|No Match| E[Insert Into Order BookPrice Level Queue] D --\u003e|Match Found| F[Select FIFO Orderat Exact Price Level] F --\u003e G[Compute Trade] G --\u003e H[Update Remaining Quantities] H --\u003e I{Order Fully Filled?} I --\u003e|Yes| J[Emit Trade Event] I --\u003e|No| F J --\u003e BCT[Background Consumer Thread: Receive Trade Event] BCT --\u003e EP[Event Publisher: Publish event to Redis Stream] Engine Dynamics # Consider the following order book:\nBACKs 10.5 -\u0026gt; [100, 80, 40, 200] 10.4 -\u0026gt; [90] LAYs 10.5 -\u0026gt; [50] 10.7 -\u0026gt; [30] The lay order at 10.5 will match against the oldest back order at the same level. The remaining unmatched back orders at that level will sit in the order book until a compatible lay is received.\nNo Match # We\u0026rsquo;re in the \u0026ldquo;No Match\u0026rdquo; branch in the diagram:\nincoming order; no opposite order found at the same price level after looking up in the order book; add order to its appropriate side in the order book at: if incoming order is a BACK then add to queue of BACK orders if incoming order is a LAY then add to queue of LAY orders Match Found # We\u0026rsquo;re in the \u0026ldquo;Match Found\u0026rdquo; branch in the diagram:\nincoming order; a lookup in the order book is performed to find an exact price level from the opposite side; from within a given price level, iterate through the FIFO queue perform partial/full fills by subtracting \\( min(incoming \\ order.value, opposite \\ order.value) \\) from both the incoming order and the opposite one trigger a trade event based on this match, using the \\( min(incoming, opposite) \\) as trade size emit trade event to the event channel check if opposite order has been filled in full, and if so remove from book check if incoming order has been filled in full, if so break iteration final pass to clean up order book from levels with no queued orders Engine Design Decisions # Separations of concerns # The engine produces (trade) events. It doesn\u0026rsquo;t handle analytics, persistence, or external communication. It stays hot and fast.\nDeterministic execution model # The engine is designed to behave as a deterministic state machine over incoming orders. That is:\ngiven the same orders (inputs), the same events (outputs) will be produced the matching logic has no hidden side effects state mutation is easily observable and incremental Partial fills # an order may not be fully matched matching can occur in increments Matching loop semantics # Matching continues until an order is fully filled or there\u0026rsquo;s no liquidity.\nOrdering guarantee # ordering is preserved within a price level fairness is guaranteed for equal-price orders Limitations and Future Work # No price-time priority across levels No distributed matching Limit orders only Externalised durability and recovery These limitations are deliberate and keep the implementation focused on deterministic matching behaviour rather than exchange infrastructure concerns.\nSelected Code Snippets # The core system lives in engine.rs:\nClick me to show/hide code // engine.rs use std::collections::VecDeque; use tokio::sync::mpsc::Sender as TokioSender; use uuid::Uuid; use crate::domain::market::MarketStatus; use crate::domain::order::{Order, OrderSide}; use crate::domain::stake::Stake; use crate::domain::trade::Trade; use crate::matching_engine::order_book::OrderBook; /// A matching engine will contain the order book for one market only. /// /// This simplifies the design. pub struct MatchingEngine { pub order_book: OrderBook, pub event_sender: TokioSender\u0026lt;Trade\u0026gt; } impl MatchingEngine { pub fn new(order_book: OrderBook, event_sender: TokioSender\u0026lt;Trade\u0026gt;) -\u0026gt; MatchingEngine { MatchingEngine { order_book, event_sender, } } /// Processes a new order. /// /// When a new order arrives it needs to be validated, and then /// if validation passes, only two outcomes can happen: /// /// 1. no compatible orders exist, and the new order cannot be immediately matched, /// so insert into order book /// 2. at least one compatible order exists so match orders and execute the trade /// /// When 2. happens, after the trade has been executed we need to update quantities /// and if the order cannot be filled in full then the remainder needs to be added /// to the order book pub fn process_order(\u0026amp;mut self, mut order: Order) -\u0026gt; Result\u0026lt;(), String\u0026gt; { if self.validate_order(\u0026amp;order) == false { return Err(String::from(\u0026#34;Invalid order submitted\u0026#34;)) } // attempt to match the incoming order to the opposite side match order.side { // search LAYs at the current odds, if any OrderSide::Back =\u0026gt; { // there\u0026#39;s a match so fulfill order; we want to match the inbound order to // as many orders as possible from the opposite side of the order book // -- this generates trading activity if let Some(_) = self.order_book.lays.get_mut(\u0026amp;order.odds) { self.match_order(order); } // no match, so add to order book as is else { self.insert_order(order); } }, // search BACKs at the current odds, if any OrderSide::Lay =\u0026gt; { // there\u0026#39;s a match -\u0026gt; trades generated if let Some(_) = self.order_book.backs.get_mut(\u0026amp;order.odds) { self.match_order(order); } // no match else { self.insert_order(order); } } } Ok(()) } fn validate_order(\u0026amp;self, order: \u0026amp;Order) -\u0026gt; bool { if order.remaining_stake.value \u0026lt;= 0 { return false } if order.odds.ticks \u0026lt;= 0 { return false } if order.market_id != self.order_book.market.market_id { return false } if self.order_book.market.status != MarketStatus::Open { return false } true } fn match_order(\u0026amp;mut self, mut order: Order) { let mut empty_lays = Vec::new(); let mut empty_backs = Vec::new(); let orders = match order.side { OrderSide::Back =\u0026gt; self.order_book.lays.get_mut(\u0026amp;order.odds), OrderSide::Lay =\u0026gt; self.order_book.backs.get_mut(\u0026amp;order.odds) }; if let Some(orders) = orders { while order.remaining_stake.value \u0026gt; 0 \u0026amp;\u0026amp; orders.len() \u0026gt; 0 { while let Some(opposite_order) = orders.front_mut() { let stake_size = order.remaining_stake.value .min(opposite_order.remaining_stake.value); let (back_order_id, lay_order_id) = match order.side { OrderSide::Back =\u0026gt; (order.order_id, opposite_order.order_id), OrderSide::Lay =\u0026gt; (opposite_order.order_id, order.order_id) }; self.event_sender.try_send(Trade::new( Uuid::new_v4(), order.market_id, order.odds.clone(), Stake::new(stake_size), back_order_id, lay_order_id )).expect(\u0026#34;Failed to send trade\u0026#34;); order.remaining_stake.value -= stake_size; opposite_order.remaining_stake.value -= stake_size; if opposite_order.remaining_stake.value == 0 { orders.pop_front(); } if orders.is_empty() { match order.side { OrderSide::Back =\u0026gt; { empty_lays.push(\u0026amp;order.odds) }, OrderSide::Lay =\u0026gt; { empty_backs.push(\u0026amp;order.odds) }, }; } if order.remaining_stake.value == 0 { break; } }; } } for level in empty_backs { self.order_book.backs.remove(level); } for level in empty_lays { self.order_book.lays.remove(level); } } fn insert_order(\u0026amp;mut self, order: Order) { let odds = order.odds.clone(); match order.side { OrderSide::Back =\u0026gt; { self.order_book.backs.entry(odds) .or_insert_with(VecDeque::new) .push_back(order); }, OrderSide::Lay =\u0026gt; { self.order_book.lays.entry(odds) .or_insert_with(VecDeque::new) .push_back(order); }, } } } The main function process_order accepts an Order and handles it as described above. From within this function, two other important functions are called, match_order and insert_order. Their names are indicative of their functionality and respectively correspond to the \u0026ldquo;Match Found\u0026rdquo; and \u0026ldquo;No Match\u0026rdquo; branches in the diagram.\nWhen a match is found the engine emits a trade event through an asynchronous Multi Producer Single Consumer (MPSC) channel:\nself.event_sender.try_send(Trade::new(...)) Throughout this article we\u0026rsquo;ve treated the order book as an implementation detail of the matching engine. In reality, the order book is the central data structure that makes deterministic matching possible.\nIn the next article we\u0026rsquo;ll examine its internal representation, how orders are organised by odds level, and why the chosen data structures make FIFO matching efficient.\n","date":"1 June 2026","externalUrl":null,"permalink":"/projects/rust_betting_exchange_2/","section":"Projects","summary":"","title":"Part II — Inside the Order Matching Engine","type":"projects"},{"content":" Most software developers have built a REST API or a database-backed service. Far fewer have built the core of a marketplace: the order matching engine (OME).\nAs a systems programming exercise, I built a simplified betting exchange in Rust. The project explores order matching, event-driven architectures, and asynchronous processing pipelines. At its core is an in-memory matching engine that emits trade events into Redis Streams, where independent Python services consume them for analytics and persistence.\nThis article provides a high-level overview of the architecture. Later posts will dive into the matching engine, order book design, and event processing pipeline.\nThe following flowchart shows how the data flows within the system:\nflowchart TD IO[Incoming Orders] LB[\"Load Balancers (Optional)\"] IA[Ingestion API] Engine[Rust Order Matching Engine] MQ[Redis Streams] DS[Asynchronous Python Services] A[Analytics] S[Storage] DB[Database] WWW[Clients: Web, Mobile, etc.] IO -.-\u003e |HTTPS / WebSockets / RPC| LB LB -.-\u003e |HTTP / HTTPS / Unix sockets| IA IA -.-\u003e Engine Engine --\u003e |Asynchronous channel communication| MQ MQ --\u003e |Event Streaming| DS A -.-\u003e WWW DS --\u003e A DS --\u003e S S --\u003e DB style IO fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 style LB fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 style IA fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 style WWW fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 Note: the orange rectangles are out of scope for this project.\nThe system is divided into two execution paths:\nHot path: order matching and trade generation Cold path: analytics, persistence, and downstream processing The Rust matching engine generates trade events which are published to Redis Streams via a background worker. Downstream services consume these events independently and process them according to their own requirements.\nDesign decisions # Pros # The architecture is built around a separation between the hot path and the cold path.\nHot path:\nIn-memory Rust matching engine Deterministic order processing No external I/O Trade generation Cold path:\nRedis Streams Analytics services Persistence services Reporting and dashboards Benefits:\nLow-latency matching Failure isolation Independent service evolution Replayable event stream Although simplified compared to production exchange systems, this architecture captures the essential idea of modern event-driven design: keep the critical decision-making path minimal and deterministic, and move everything else into asynchronous, replayable processing pipelines.\nCons # This architecture introduces several trade-offs:\nEventual consistency between trade execution and downstream consumers Dependence on Redis as the event backbone No distributed matching or order book replication No explicit latency or throughput guarantees These trade-offs were intentional and allow the project to focus on event-driven architecture rather than production-scale exchange infrastructure.\nTech. stack # Component Technology Reason Matching Engine Rust Performance, memory safety, deterministic execution Event Backbone Redis Streams Replayability, consumer groups, operational simplicity Downstream Services Python Fast development and strong analytics ecosystem Together, these technologies form a layered architecture: a high-performance deterministic core in Rust, an event distribution layer via Redis Streams, and flexible consumer services in Python for secondary processing tasks. This separation allows each layer to optimise for different constraints without compromising the others.\nThis architecture intentionally separates order matching from downstream processing through an event-driven pipeline. The result is a small but representative example of how modern trading systems isolate latency-sensitive execution from analytics and persistence concerns.\nIn the next article, we\u0026rsquo;ll dive into the matching engine itself and examine how orders are matched and trade events are generated.\nNOTE: as we progress through this series, if confused, it helps to return to the diagram above, to keep track of what layer is being discussed.\n","date":"1 June 2026","externalUrl":null,"permalink":"/projects/rust_betting_exchange_1/","section":"Projects","summary":"","title":"Part I — Inside the Event-driven Betting Exchange Architecture","type":"projects"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/algorithmic-trading/","section":"Tags","summary":"","title":"Algorithmic Trading","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/application-infrastructure/","section":"Tags","summary":"","title":"Application Infrastructure","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/backtester/","section":"Tags","summary":"","title":"Backtester","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/backtesting/","section":"Tags","summary":"","title":"Backtesting","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/event-driven/","section":"Tags","summary":"","title":"Event-Driven","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/quant/","section":"Tags","summary":"","title":"Quant","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/series/retroedge/","section":"Series","summary":"","title":"Retroedge","type":"series"},{"content":"The previous article described the application\u0026rsquo;s architecture. This article focuses on the execution model: how data flows through the engine and how the different components interact during a backtest.\nThere are several ways to implement a backtesting engine. _Retroedge_uses an event-driven model because it closely mirrors the behaviour of a live trading system. Rather than processing an entire dataset in a single pass, market data arrives one event at a time, allowing strategies, portfolio management, and execution to react in a way that resembles live trading.\nThe engine revolves around four event types:\nMarketEvent \u0026ndash; new market data becomes available SignalEvent \u0026ndash; a strategy decides to buy or sell OrderEvent \u0026ndash; an order is submitted for execution FillEvent \u0026ndash; an order has been executed With the above in mind, at a high level, the engine reduces to the following control loop:\nloop { data_handler.next_bar(); while let Some(event) = queue.pop() { match event { MarketEvent =\u0026gt; strategy.on_market(), SignalEvent =\u0026gt; portfolio.on_signal(), OrderEvent =\u0026gt; broker.execute(), FillEvent =\u0026gt; portfolio.on_fill(), } } } Event lifecycle # %%{init: {\"flowchart\": {\"useMaxWidth\": true}, \"themeVariables\": {\"fontSize\": \"64px\"}}}%% flowchart LR M[Market Event] S[Strategy] RM[Risk Manager] SE[Signal Event] ORE[Order Request Event] PM[Portfolio Manager] OE[Order Event] B[Broker] FE[Fill Event] M --\u003e S S --\u003e SE SE --\u003e RM RM --\u003e ORE ORE --\u003e PM PM --\u003e OE OE --\u003e B B --\u003e FE FE --\u003e PM Each component has a single responsibility and communicates exclusively through events. This keeps the engine loosely coupled: strategies can be replaced without modifying the broker, execution models can change without affecting the portfolio, and new event types can be introduced with minimal impact elsewhere.\nVectorised vs event-driven # Vectorised backtests are often simpler to implement and can be considerably faster for certain classes of strategy. The trade-off is that they process the entire dataset at once, whereas an event-driven engine processes information incrementally. Although this introduces additional complexity, it more closely reflects how a live trading system receives and reacts to market data.\nThis event loop forms the backbone of the entire engine. Every subsystem participates by consuming events, performing a small piece of work, and emitting new events when appropriate.\nThe next article examines these individual components in greater detail and discusses how they evolve when moving from historical simulation to live trading.\n","date":"16 February 2026","externalUrl":null,"permalink":"/projects/rust_backtester_3/","section":"Projects","summary":"","title":"Retroedge - Application Logic - Part 3","type":"projects"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/server-infrastructure/","section":"Tags","summary":"","title":"Server Infrastructure","type":"tags"},{"content":"The previous article covered the deployment architecture. This article focuses on the application architecture and how requests flow through the system.\ngraph TD U[Users / Browser] FE[Frontend AppUI] API[Backend REST API] DB[(Database)] U --\u003e |HTTP Request| FE FE --\u003e |HTTP Response| U FE --\u003e|HTTP Request| API API --\u003e|HTTP Response| FE DB --\u003e|ETL| API API --\u003e|Write| DB The application is split into three logical components: a frontend, a REST API, and a persistence layer. Requests originate in the browser, pass through the frontend, and are forwarded to the API only when additional data or server-side processing is required. Likewise, the API interacts with the database only when necessary.\nWhy use a layered architecture instead of a monolith? # A monolithic application would certainly be simpler. However, the backend originally existed as a command-line tool before a web interface was introduced. Preserving that separation allows the core engine to remain usable both interactively through the UI and offline through the CLI.\nBenefits # clear separation of responsibilities; frontend and backend evolve independently; backend remains usable through both the web UI and CLI; the UI has no direct access to persistence; shorter deployment and testing cycles; simpler debugging and maintenance. One consequence of separating the frontend and backend is that both sides must agree on the API contract. Frameworks such as GraphQL attempt to address this problem. For RetroEdge, however, a conventional REST API backed by well-defined JSON payloads is sufficient and avoids introducing another layer of complexity.\nStandards such as JSON:API can also help formalise these contracts without introducing an entirely new query language.\nTrade-offs # greater architectural complexity than a monolith; frontend and backend contracts must remain compatible; end-to-end testing spans multiple components. Tech stack # Component Technology Reason Frontend Dioxus Web Rust UI Server Axum HTTP routing and middleware Styling Tailwind CSS Utility-first CSS Persistence CSV Lightweight storage during development Isomorphic Rust, is that a thing? What is it the future? # A pleasant side effect of using Dioxus is that much of the application can be written in Rust rather than maintaining separate JavaScript and backend codebases. The idea is similar to the \u0026ldquo;isomorphic JavaScript\u0026rdquo; movement from several years ago, but applied to Rust instead.\nAlthough the project uses Dioxus Fullstack, most of the server-side implementation is built directly on Axum. Dioxus makes this transition straightforward, allowing lower-level control where needed.\nThe current implementation stores data as CSV files rather than using a relational database. This is sufficient for the current workload, and the storage layer is abstracted so that SQLite or PostgreSQL can be introduced later without affecting the rest of the application.\nWith the architectural groundwork in place, the next article begins exploring the implementation itself.\n","date":"15 December 2025","externalUrl":null,"permalink":"/projects/rust_backtester_2/","section":"Projects","summary":"","title":"Retroedge - Application Architecture - Part 2","type":"projects"},{"content":"","date":"15 December 2025","externalUrl":null,"permalink":"/tags/architecture/","section":"Tags","summary":"","title":"Architecture","type":"tags"},{"content":"","date":"15 December 2025","externalUrl":null,"permalink":"/tags/infrastructure/","section":"Tags","summary":"","title":"Infrastructure","type":"tags"},{"content":"I\u0026rsquo;ve just released v0.1.0 of a Rust-based Backtesting engine on:\nhttps://retroedge.io/\nIt is a complete rewrite of the previous Python implementation, with a focus on performance, maintainability, and future extensibility. The original implementation is documented in the a previous series.\nWhy bother rewriting it in Rust from Python? # \u0026ldquo;If it ain\u0026rsquo;t broke don\u0026rsquo;t fix it\u0026rdquo;, right? It wasn\u0026rsquo;t broken but could be better.\nPython has an exceptional ecosystem for rapid prototyping and quantitative computing. However, for a latency-sensitive application where performance is a primary design constraint, Rust provides stronger control over memory, concurrency, execution costs, and native zero-cost abstractions without relying on Python-to-C FFI boundaries.\nWhy Rust and not C++ for a Trading application? # Rust offers performance comparable to C and C++ while providing stronger guarantees around memory safety and concurrency.\nAlthough Rust\u0026rsquo;s ecosystem is younger than those of Python or C++, the language itself provides strong primitives for building the missing pieces when required.\nI also considered other candidates like: Go, C#, Java, but needed a language that allowed for fine-tuned performance optimisations down the line if needed. Go and its garbage collection,\nBefore discussing the application architecture, it is worth looking at the overall system architecture.\nDeployment Architecture # %%{init: {\"flowchart\": {\"useMaxWidth\": true}, \"themeVariables\": {\"fontSize\": \"32px\"}}}%% flowchart LR U[Users / Clients] LB[Proxy Server \u0026 Load Balancer] subgraph CI[CI \u0026 CD] C1[\"CI Server (Build \u0026 Test)\"] C2[\"CD Server (Deploy)\"] end subgraph APP[Application Servers] A1[App Server #1] A2[App Server #2] A3[App Sferver #N] end API[API] DB[(Database)] U --\u003e LB LB --\u003e A1 LB --\u003e A2 LB --\u003e A3 A1 --\u003e API A2 --\u003e API A3 --\u003e API API --\u003e DB C1 --\u003e C2 C2 -.-\u003e|Deploy| A1 C2 -.-\u003e|Deploy| A2 C2 -.-\u003e|Deploy| A3 style LB fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 style A2 fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 style A3 fill:#F28C28,stroke:#FFFFFF,stroke-dasharray: 5 5,color:#000000 The load balancer is not actually part of the architecture, but has been added to show where it would fit in. Same for the App Server #2 and #3.\nBenefits # I\u0026rsquo;m fond of this structure because it encourages system-wide separation of concerns:\nload balancing; stateless application servers only serving client requests; stateful API responsible for business logic; simpler development, testing, and debuggin; scalability \u0026ndash; can add more application servers if the load demands it; resilience \u0026ndash; if one of the application servers is down another can pick up the slack (*); high availability through redundant application servers; security \u0026ndash; the API is behind multiple layers (*) this helps with fault tolerance and redundancy only partially, as it is all on the same machine. True redundancy requires deployment across multiple hosts.\nTrade-offs # increased operational complexity; more involved deployment; single point of failure in the load balancer. The last point can be mitigated by making the load balancer itself redundant, but it\u0026rsquo;s similar to the resilience point: if it\u0026rsquo;s all on the same machine and it\u0026rsquo;s down for whatever reason, e.g. power outage, etc., the whole thing won\u0026rsquo;t work.\nDevOps # The CI/CD pipeline is orthogonal to the request flow and exists solely to support development. New commits trigger the CI pipeline, which builds the project and executes the test suite. Successful builds can then be deployed through the CD pipeline.\nOnce the CI server green lights the changes, the CD flow can take over and deploy them to the live environment. Note: you can have Continuous Delivery without the delivery being automated. To mitigate risk I prefer to manually click the deploy button, even if the actual deployment is automated.\nTo container or not to container; that is the question # For this project I decided not to containerise the services. The deployment targets are well understood, and native deployments are simpler operationally while avoiding an additional abstraction layer. Containers can be valuable when portability, orchestration, or heterogeneous environments become requirements, but they would add complexity without solving a problem this project currently has.\nThis concludes the overview of the system architecture.\nIn the next article we will cover the application-level architecture.\n","date":"15 December 2025","externalUrl":null,"permalink":"/projects/rust_backtester_1/","section":"Projects","summary":"","title":"Retroedge - System Architecture - Part 1","type":"projects"},{"content":" Setup Dioxus (version 0.7.x) # To set up the Dioxus framework follow their well-written getting started guide.\nOnce all is set up, you can create a new app with:\ndx new app_name\nand follow the interactive prompts to pick project specifics and target, i.e. Web, Desktop, etc.\nThe command above will create the necessary scaffolding.\nYou can now launch the dev server with:\ndx serve\nto check that all went smoothly. If something went wrong refer to their tooling setup guide.\nSetup Tailwind CSS (version 4.1.x) # Follow the official process at:\nhttps://tailwindcss.com/docs/installation/tailwind-cli\nto install Tailwind itself and its CLI utility for a framework-agnostic setup.\nThe above commands require Node and npm. On my machine they\u0026rsquo;re versions:\n$ node --version v22.14.0 $ npm --version 10.9.2 Integrate Tailwind CSS into Dioxus # Add Tailwind to your main CSS file, i.e. if it\u0026rsquo;s input.css,\n/* input.css */ @import \u0026#34;tailwindcss\u0026#34;; /* Ignore \u0026#34;cannot resolve\u0026#34; dependency warnings in the import above. If tailwind is installed in the node_modules folder, it will be resolved correctly. */ /* Rest of styling */ In the package.json at the root of the project, add the following key:\n\u0026#34;scripts\u0026#34;: { \u0026#34;tailwind\u0026#34;: \u0026#34;npx @tailwindcss/cli -i ./assets/input.css -o ./assets/output.css --watch\u0026#34; } and execute with:\n$ npm run tailwind to run tailwind cli in watch mode, which rebuilds styling sources automatically when they change.\nWhen all the steps above are in place, you should have one terminal running dx serve and another running npm run tailwind.\nAdd the generated css file to your Dioxus application # use dioxus::prelude::*; const APP_STYLE: Asset = asset!(\u0026#34;assets/output.css\u0026#34;); fn main() { launch(app) } fn app() -\u0026gt; Element { rsx! { Stylesheet { href: APP_STYLE }, // use Tailwind classes in your code h1 { class: \u0026#34;text-center text-blue-600\u0026#34;, \u0026#34;Hello World\u0026#34; } } } And that\u0026rsquo;s it!\nPotential flaw of this approach # A potential flaw of this approach is that it doesn\u0026rsquo;t leverage the Dioxus.toml file generated by the dx new app_name command, and integrate the css infrastructure directly into Dioxus\u0026rsquo; dev server. Theoretically, said integration should allow css refresh and app changes to be rebuilt and reloaded with only the dx serve command. However, I couldn\u0026rsquo;t find up-to-date instructions from their docs so went with the above.\n","date":"6 November 2025","externalUrl":null,"permalink":"/howtos/dioxus_tailwindcss_setup/","section":"Howtos","summary":"","title":"Dioxus and Tailwind CSS Setup","type":"howtos"},{"content":"","date":"6 November 2025","externalUrl":null,"permalink":"/howtos/","section":"Howtos","summary":"","title":"Howtos","type":"howtos"},{"content":"In the previous article we took a deep dive in the Portfolio component and discussed its role in communicating with the signal generator and the broker. In this article we will expand on the relationship between Portfolio and Broker.\nThe Broker component is concerned only with executing orders. It doesn\u0026rsquo;t need to involve itself with other components, except the Portfolio, and as such will be a \u0026ldquo;dumb\u0026rdquo; component. In a live implementation it will need to be more involved, but for a naive buy \u0026amp; hold strategy, we can get by with a dumb broker.\nThe final code for the broker is:\n# trading_engine/broker.py import datetime from abc import ABC, abstractmethod from events import FillEvent class ExecutionHandler(ABC): \u0026#34;\u0026#34;\u0026#34; The ExecutionHandler abstract base class handles the interaction between a set of order objects generated by a Portfolio and the ultimate set of Fill objects that actually occur in the market. The derived handlers can be used to subclass simulated or live brokerages, with identical interfaces. This allows strategies to be backtested in a very similar environment to a live trading engine. \u0026#34;\u0026#34;\u0026#34; @abstractmethod def execute_order(self, event): \u0026#34;\u0026#34;\u0026#34; Takes an Order event and executes it, producing a Fill event that gets placed onto the events queue. :param event: an OrderEvent object \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement execute_order()\u0026#34;) class SimulatedExecutionHandler(ExecutionHandler): \u0026#34;\u0026#34;\u0026#34; The SimulatedExecutionHandler simply converts all order objects into their equivalent fill objects in a \u0026#34;dumb\u0026#34; manner, without latency, slippage or fill-ratio issues. More realistic implementations will have to implement those. \u0026#34;\u0026#34;\u0026#34; def __init__(self, events): \u0026#34;\u0026#34;\u0026#34; Initialise the handler, setting the event queues internally :param events: the queue of Event objects \u0026#34;\u0026#34;\u0026#34; self.events = events def execute_order(self, event): \u0026#34;\u0026#34;\u0026#34; Simply converts Order objects into Fill objects, naively, as explained in the main docstring. :param event: an OrderEvent object \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#39;ORDER\u0026#39;: event.print_order() fill_event = FillEvent( datetime.datetime.now(datetime.UTC), event.symbol, \u0026#39;ARCA\u0026#39;, event.quantity, # In a simulated environment ordered quantity = filled quantity, # but in a real world setting the quantities may differ, due to # slippage -- the broker not being able to fill the order entirely, # or not at the initially agreed price. # event.filled_quantity, event.direction, # fill cost is None for simplicity, but in a real setting it should be # computed here or more commonly sent from the broker\u0026#39;s platform directly None ) self.events.put(fill_event) The execute_order method, which simply converts an OrderEvent to a FillEvent.\nAdding on the code comments in the method, a smarter broker will also inform the Portfolio about leveraged positions and warn about the dreaded margin calls. Moreover, a broker could also be the data source, but for the sake of illustration, it conceptually makes sense to abstract the two into their own parts. After all the main data layer could originate from another source and not the broker\u0026rsquo;s data feed, or even if the data is coming from the broker, separating data from execution is the sensible thing to do.\nThat concludes the series. If you followed it all the way here then you can pat yourself on the back!\nConcluding remarks # If you refer back to the first article, and the first code snippet, you will hopefully have a complete understanding of how the pieces weld together, how to cover application code with tests, how a backtesting engine works in its simplest form, and more generally how to develop an event-driven system and apply it to whatever other domain you\u0026rsquo;re concerned with.\nIf you want to reach out for whatever reason, to inform me of errors, questions, etc., you can do so via email here or Linkedin.\n","date":"4 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_7/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Broker - Part 7","type":"projects"},{"content":"In the previous article we discussed the Strategy component and its role in generating trading signals in line with the strategy logic.\nIn this article we\u0026rsquo;ll go through a central part of the system, the Portfolio component. This component communicates with multiple other parts of the system. For example on one side it takes in signals from the Signal layer, on the other it generates order events to be passed on to the Broker component, and then later does the bookkeeping to calculate exposure (in terms of positions and cash), PnL, etc. after the order has been filled by the broker.\nThe final code for the Portfolio is:\nDetails # trading_engine/portfolio.py import pandas as pd from abc import ABC, abstractmethod from math import floor from events import OrderEvent from performance import create_sharpe_ratio, create_drawdowns class Portfolio(ABC): \u0026#34;\u0026#34;\u0026#34; The Portfolio class handles the positions and market value of all instruments at a resolution of a \u0026#34;bar\u0026#34;, i.e., secondly, minutely, hourly, etc. \u0026#34;\u0026#34;\u0026#34; @abstractmethod def update_signal(self, event): \u0026#34;\u0026#34;\u0026#34; Acts on a SignalEvent to generate new orders based on the portfolio logic. :param event: the Queue event object \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement update_signal()\u0026#34;) @abstractmethod def update_fill(self, event): \u0026#34;\u0026#34;\u0026#34; Updates the portfolio current positions and holdings from a FillEvent. :param event: a FillEvent object \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement update_fill()\u0026#34;) class BuyAndHoldPortfolio(Portfolio): \u0026#34;\u0026#34;\u0026#34; The BuyAndHoldPortfolio is designed to send orders to a brokerage object with a specified quantity and size. \u0026#34;\u0026#34;\u0026#34; def __init__(self, bars, events, start_date, initial_capital=100000.0): \u0026#34;\u0026#34;\u0026#34; Initialises the portfolio with bars, an event queue, a starting time index, and initial capital (in USD unless stated otherwise). :param bars: the DataHandler object with current market data -\u0026gt; pandas-like obj :param events: the Event queue object _\u0026gt; Queue :param start_date: the start date (bar) of the portfolio -\u0026gt; datetime :param initial_capital: the starting capital in USD -\u0026gt; float \u0026#34;\u0026#34;\u0026#34; self.bars = bars self.events = events self.symbol_list = self.bars.symbol_list self.start_date = start_date self.initial_capital = initial_capital self.all_positions = self.construct_all_positions() self.current_positions = {k: v for k, v in [(s, 0) for s in self.symbol_list]} self.all_holdings = self.construct_all_holdings() self.current_holdings = self.construct_current_holdings() def construct_all_positions(self): \u0026#34;\u0026#34;\u0026#34; Constructs the positions list using the start_date attribute to determine when the time index will begin. \u0026#34;\u0026#34;\u0026#34; d = {k: v for k, v in [(s, 0) for s in self.symbol_list]} d[\u0026#39;datetime\u0026#39;] = self.start_date return [d] def construct_all_holdings(self): \u0026#34;\u0026#34;\u0026#34; Constructs the holdings list using the start_date to determine when the time index will begin. \u0026#34;\u0026#34;\u0026#34; d = {k: v for k, v in [(s, 0.0) for s in self.symbol_list]} d[\u0026#39;datetime\u0026#39;] = self.start_date d[\u0026#39;cash\u0026#39;] = self.initial_capital d[\u0026#39;commission\u0026#39;] = 0.0 d[\u0026#39;total\u0026#39;] = self.initial_capital return [d] def construct_current_holdings(self): \u0026#34;\u0026#34;\u0026#34; This constructs the dictionary which will hold the instantaneous value of the portfolio across all symbols. \u0026#34;\u0026#34;\u0026#34; d = {k: v for k, v in [(s, 0.0) for s in self.symbol_list]} d[\u0026#39;cash\u0026#39;] = self.initial_capital d[\u0026#39;commission\u0026#39;] = 0.0 d[\u0026#39;total\u0026#39;] = self.initial_capital return d def update_timeindex(self, event): \u0026#34;\u0026#34;\u0026#34; Adds a new record to the positions matrix for the current market data bar. This reflects the PREVIOUS bar, i.e., all current market data at this state is known (OHLCVI). Makes use of a MarketEvent from the events queue. N.B. this doesn\u0026#39;t update the actual position values -- those are updated after a FillEvent. :param event: a MarketEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#34;MARKET\u0026#34;: bars = {} for sym in self.symbol_list: bars[sym] = self.bars.get_latest_bars(sym, N=1) # update positions dp = {k: v for k, v in [(s, 0) for s in self.symbol_list]} dp[\u0026#39;datetime\u0026#39;] = bars[self.symbol_list[0]][0][1] for s in self.symbol_list: dp[s] = self.current_positions[s] # append the current positions self.all_positions.append(dp) # update holdings dh = {k: v for k, v in [(s, 0) for s in self.symbol_list]} dh[\u0026#39;datetime\u0026#39;] = bars[self.symbol_list[0]][0][1] dh[\u0026#39;cash\u0026#39;] = self.current_holdings[\u0026#39;cash\u0026#39;] dh[\u0026#39;commission\u0026#39;] = self.current_holdings[\u0026#39;commission\u0026#39;] dh[\u0026#39;total\u0026#39;] = self.current_holdings[\u0026#39;cash\u0026#39;] for s in self.symbol_list: # bars[s][0][5] = close price of the symbol; an approximation to the market value market_value = self.current_positions[s] * bars[s][0][5] dh[s] = market_value dh[\u0026#39;total\u0026#39;] += market_value # append the current holdings self.all_holdings.append(dh) def update_positions_from_fill(self, fill): \u0026#34;\u0026#34;\u0026#34; Takes a FillEvent object and updates the positions matrix to reflect new positions. :param fill: the FillEvent to update positions with -\u0026gt; Event \u0026#34;\u0026#34;\u0026#34; fill_dir = 0 if fill.direction == \u0026#39;BUY\u0026#39;: fill_dir = 1 elif fill.direction == \u0026#39;SELL\u0026#39;: fill_dir = -1 self.current_positions[fill.symbol] += fill_dir * fill.filled_quantity def update_holdings_from_fill(self, fill): \u0026#34;\u0026#34;\u0026#34; Takes a FillEvent object and updates the holdings matrix to reflect the holdings value. :param fill: a FillEvent object \u0026#34;\u0026#34;\u0026#34; fill_dir = 0 if fill.direction == \u0026#39;BUY\u0026#39;: fill_dir = 1 if fill.direction == \u0026#39;SELL\u0026#39;: fill_dir = -1 # update holdings list with new quantities fill_cost = self.bars.get_latest_bars(fill.symbol)[0][5] # close price cost = fill_dir * fill_cost self.current_holdings[fill.symbol] += cost self.current_holdings[\u0026#39;commission\u0026#39;] += fill.commission self.current_holdings[\u0026#39;cash\u0026#39;] -= (cost + fill.commission) self.current_holdings[\u0026#39;total\u0026#39;] -= (cost + fill.commission) def update_fill(self, event): \u0026#34;\u0026#34;\u0026#34; Updates the portfolio current positions and holdings from a FillEvent. :param event: a FillEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#39;FILL\u0026#39;: event.print_order() self.update_positions_from_fill(event) self.update_holdings_from_fill(event) def generate_naive_order(self, signal): \u0026#34;\u0026#34;\u0026#34; Simply transact an OrderEvent object with a specified quantity of the symbol(s) in the signal :param signal: a SignalEvent object \u0026#34;\u0026#34;\u0026#34; order = None symbol = signal.symbol direction = signal.signal_type strength = signal.strength max_cash_per_trade = 0.10 * self.current_holdings[\u0026#39;cash\u0026#39;] # max. 10% cash per trade # position size = max cash per trade / unit cost of asset position_size = max_cash_per_trade // self.bars.get_latest_bars(symbol, N=1)[0][5] # [5] = closing price mkt_quantity = floor(position_size * strength) # floor() rounds to lower integer -- no fractional shares curr_quantity = self.current_positions[symbol] order_type = \u0026#39;MKT\u0026#39; if direction == \u0026#39;LONG\u0026#39; and curr_quantity == 0: order = OrderEvent(symbol, order_type, mkt_quantity, \u0026#39;BUY\u0026#39;) if direction == \u0026#39;SHORT\u0026#39; and curr_quantity == 0: order = OrderEvent(symbol, order_type, mkt_quantity, \u0026#39;SELL\u0026#39;) if direction == \u0026#39;EXIT\u0026#39; and curr_quantity \u0026gt; 0: order = OrderEvent(symbol, order_type, abs(curr_quantity), \u0026#39;SELL\u0026#39;) if direction == \u0026#39;EXIT\u0026#39; and curr_quantity \u0026lt; 0: order = OrderEvent(symbol, order_type, abs(curr_quantity), \u0026#39;BUY\u0026#39;) return order def update_signal(self, event): \u0026#34;\u0026#34;\u0026#34; Acts on a SignalEvent to generate new orders based on portfolio logic. :param event: a SignalEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#39;SIGNAL\u0026#39;: order_event = self.generate_naive_order(event) self.events.put(order_event) def create_equity_curve_dataframe(self): \u0026#34;\u0026#34;\u0026#34; Creates a pandas Dataframe from the all holdings structure. \u0026#34;\u0026#34;\u0026#34; curve = pd.DataFrame(self.all_holdings) curve.set_index(\u0026#39;datetime\u0026#39;, inplace=True) curve[\u0026#39;returns\u0026#39;] = curve[\u0026#39;total\u0026#39;].pct_change() curve[\u0026#39;equity_curve\u0026#39;] = (1.0 + curve[\u0026#39;returns\u0026#39;]).cumprod() self.equity_curve = curve def output_summary_stats(self, periods=\u0026#34;days\u0026#34;): \u0026#34;\u0026#34;\u0026#34; Creates a list of output summary statistics for the portfolio such as Sharpe Ratio and drawdown info. :param periods: max drawdown duration periods, either in days, weeks, years, depnding on data frequency -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; total_return = self.equity_curve[\u0026#39;equity_curve\u0026#39;].iloc[-1] returns = self.equity_curve[\u0026#39;returns\u0026#39;] pnl = self.equity_curve[\u0026#39;equity_curve\u0026#39;] sharpe_ratio = create_sharpe_ratio(returns) max_dd, dd_duration = create_drawdowns(pnl) stats = [ f\u0026#34;Initial cash balance ${self.initial_capital:0,.2f}\u0026#34;, f\u0026#34;Final cash balance ${self.all_holdings[-1][\u0026#39;cash\u0026#39;]:0,.2f}\u0026#34;, f\u0026#34;Final account value ${self.all_holdings[-1][\u0026#39;total\u0026#39;]:0,.2f}\u0026#34;, f\u0026#34;Total Return {(total_return - 1.0) * 100.0:0.2f}%\u0026#34;, f\u0026#34;Sharpe Ratio {sharpe_ratio:0.4f}\u0026#34;, f\u0026#34;Max Drawdown {max_dd * 100.0:0.2f}%\u0026#34;, f\u0026#34;Max Drawdown Duration {dd_duration:g} {periods}\u0026#34; ] return stats However, we\u0026rsquo;ll go through the most significant parts to better understand the whole. Starting from the __init__ method,\n# trading_engine/portfolio.py # [...] class BuyAndHoldPortfolio(Portfolio): \u0026#34;\u0026#34;\u0026#34; The BuyAndHoldPortfolio is designed to send orders to a brokerage object with a specified quantity and size. \u0026#34;\u0026#34;\u0026#34; def __init__(self, bars, events, start_date, initial_capital=100000.0): \u0026#34;\u0026#34;\u0026#34; Initialises the portfolio with bars, an event queue, a starting time index, and initial capital (in USD unless stated otherwise). :param bars: the DataHandler object with current market data -\u0026gt; pandas-like obj :param events: the Event queue object _\u0026gt; Queue :param start_date: the start date (bar) of the portfolio -\u0026gt; datetime :param initial_capital: the starting capital in USD -\u0026gt; float \u0026#34;\u0026#34;\u0026#34; self.bars = bars self.events = events self.symbol_list = self.bars.symbol_list self.start_date = start_date self.initial_capital = initial_capital self.all_positions = self.construct_all_positions() self.current_positions = {k: v for k, v in [(s, 0) for s in self.symbol_list]} self.all_holdings = self.construct_all_holdings() self.current_holdings = self.construct_current_holdings() The key parts are the last four lines that respectively build dicts for keeping track of all positions; current positions; all holdings; and current holdings. In Python parlance a dict is what is considered a hash map in other programming languages. Positions are simply the quantities or units of the assets in the Portfolio, and the holdings are the $ quantities * price $. For the actual methods the variables are assigned to, refer to the first snippet with the final code.\nNext is the update_timeindex method,\ndef update_timeindex(self, event): \u0026#34;\u0026#34;\u0026#34; Adds a new record to the positions matrix for the current market data bar. This reflects the PREVIOUS bar, i.e., all current market data at this state is known (OHLCVI). Makes use of a MarketEvent from the events queue. N.B. this doesn\u0026#39;t update the actual position values -- those are updated after a FillEvent. :param event: a MarketEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#34;MARKET\u0026#34;: bars = {} for sym in self.symbol_list: bars[sym] = self.bars.get_latest_bars(sym, N=1) # update positions dp = {k: v for k, v in [(s, 0) for s in self.symbol_list]} dp[\u0026#39;datetime\u0026#39;] = bars[self.symbol_list[0]][0][1] for s in self.symbol_list: dp[s] = self.current_positions[s] # append the current positions self.all_positions.append(dp) # update holdings dh = {k: v for k, v in [(s, 0) for s in self.symbol_list]} dh[\u0026#39;datetime\u0026#39;] = bars[self.symbol_list[0]][0][1] dh[\u0026#39;cash\u0026#39;] = self.current_holdings[\u0026#39;cash\u0026#39;] dh[\u0026#39;commission\u0026#39;] = self.current_holdings[\u0026#39;commission\u0026#39;] dh[\u0026#39;total\u0026#39;] = self.current_holdings[\u0026#39;cash\u0026#39;] for s in self.symbol_list: # bars[s][0][5] = close price of the symbol; an approximation to the market value market_value = self.current_positions[s] * bars[s][0][5] dh[s] = market_value dh[\u0026#39;total\u0026#39;] += market_value # append the current holdings self.all_holdings.append(dh) To better simulate the passing of time and the arrival of new information in a real trading system, we will need to progressively, as market events are triggered and absorbed, adjust our positions and holdings to reflect arrival of a new data bar and thus add these new data, if any, to the Portfolio to keep it in sync with the market feed and look out for market events that lead up to a signal being generated.\nOnce a trading signal is generated, the Portfolio will capture that signal, from the update_signal(), and act on it by triggering an OrderEvent and adding it to the queue:\n# [...] def generate_naive_order(self, signal): \u0026#34;\u0026#34;\u0026#34; Simply transact an OrderEvent object with a specified quantity of the symbol(s) in the signal :param signal: a SignalEvent object \u0026#34;\u0026#34;\u0026#34; order = None symbol = signal.symbol direction = signal.signal_type strength = signal.strength max_cash_per_trade = 0.10 * self.current_holdings[\u0026#39;cash\u0026#39;] # max. 10% cash per trade # position size = max cash per trade / unit cost of asset position_size = max_cash_per_trade // self.bars.get_latest_bars(symbol, N=1)[0][5] # [5] = closing price mkt_quantity = floor(position_size * strength) # floor() rounds to lower integer, aka no fractional shares curr_quantity = self.current_positions[symbol] order_type = \u0026#39;MKT\u0026#39; if direction == \u0026#39;LONG\u0026#39; and curr_quantity == 0: order = OrderEvent(symbol, order_type, mkt_quantity, \u0026#39;BUY\u0026#39;) if direction == \u0026#39;SHORT\u0026#39; and curr_quantity == 0: order = OrderEvent(symbol, order_type, mkt_quantity, \u0026#39;SELL\u0026#39;) if direction == \u0026#39;EXIT\u0026#39; and curr_quantity \u0026gt; 0: order = OrderEvent(symbol, order_type, abs(curr_quantity), \u0026#39;SELL\u0026#39;) if direction == \u0026#39;EXIT\u0026#39; and curr_quantity \u0026lt; 0: order = OrderEvent(symbol, order_type, abs(curr_quantity), \u0026#39;BUY\u0026#39;) return order def update_signal(self, event): \u0026#34;\u0026#34;\u0026#34; Acts on a SignalEvent to generate new orders based on portfolio logic. :param event: a SignalEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#39;SIGNAL\u0026#39;: order_event = self.generate_naive_order(event) self.events.put(order_event) Refer back to the main event loop in Part 1 of the series. Once an order event is triggered, the Broker will act on it, but we will get to that later.\nNext is the update_fill method, which captures a FillEvent generated by the broker, and updates the positions, holdings, etc.,\n# [...] def update_fill(self, event): \u0026#34;\u0026#34;\u0026#34; Updates the portfolio current positions and holdings from a FillEvent. :param event: a FillEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#39;FILL\u0026#39;: event.print_order() self.update_positions_from_fill(event) self.update_holdings_from_fill(event) The two methods update_positions_from_fill and update_holdings_from_fill do what it says on the tin. You can look at their definitions in the final code at the top.\nAnd finally, we cover the create_equity_curve_dataframe and output_summary_stats:\n# [...] def create_equity_curve_dataframe(self): \u0026#34;\u0026#34;\u0026#34; Creates a pandas Dataframe from the all holdings structure. \u0026#34;\u0026#34;\u0026#34; curve = pd.DataFrame(self.all_holdings) curve.set_index(\u0026#39;datetime\u0026#39;, inplace=True) curve[\u0026#39;returns\u0026#39;] = curve[\u0026#39;total\u0026#39;].pct_change() curve[\u0026#39;equity_curve\u0026#39;] = (1.0 + curve[\u0026#39;returns\u0026#39;]).cumprod() self.equity_curve = curve def output_summary_stats(self, periods=\u0026#34;days\u0026#34;): \u0026#34;\u0026#34;\u0026#34; Creates a list of output summary statistics for the portfolio such as Sharpe Ratio and drawdown info. :param periods: max drawdown duration periods, either in days, weeks, years, depnding on data frequency -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; total_return = self.equity_curve[\u0026#39;equity_curve\u0026#39;].iloc[-1] returns = self.equity_curve[\u0026#39;returns\u0026#39;] pnl = self.equity_curve[\u0026#39;equity_curve\u0026#39;] sharpe_ratio = create_sharpe_ratio(returns) max_dd, dd_duration = create_drawdowns(pnl) stats = [ f\u0026#34;Initial cash balance ${self.initial_capital:0,.2f}\u0026#34;, f\u0026#34;Final cash balance ${self.all_holdings[-1][\u0026#39;cash\u0026#39;]:0,.2f}\u0026#34;, f\u0026#34;Final account value ${self.all_holdings[-1][\u0026#39;total\u0026#39;]:0,.2f}\u0026#34;, f\u0026#34;Total Return {(total_return - 1.0) * 100.0:0.2f}%\u0026#34;, f\u0026#34;Sharpe Ratio {sharpe_ratio:0.4f}\u0026#34;, f\u0026#34;Max Drawdown {max_dd * 100.0:0.2f}%\u0026#34;, f\u0026#34;Max Drawdown Duration {dd_duration:g} {periods}\u0026#34; ] return stats The first builds the equity curve, while the second prints key portfolio metrics to the console. You could get creative and instead of printing to console, write to a .pdf, .html, email, whatever, or a combination of those.\nThat\u0026rsquo;s it for the Portfolio.\nIn the next article we will cover the Broker component.\nPortfolio tests # # trading_engine/tests/test_portfolio.py import queue import pytest import datetime from broker import SimulatedExecutionHandler from portfolio import BuyAndHoldPortfolio from data import HistoricCsvDataHandler from strategy import BuyAndHoldStrategy from events import MarketEvent, SignalEvent, OrderEvent, FillEvent from utils import data_dir_setup, asset_class_selector, cli_parser @pytest.fixture def portfolio_setup(): # CLI data args = [\u0026#34;--asset_class\u0026#34;, \u0026#34;stocks\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD INTC\u0026#34;] parsed_args = cli_parser(args) asset_class = asset_class_selector(parsed_args) # Assets data data_dir = data_dir_setup(asset_class) # Event queue events = queue.Queue() # The symbols below match those hard-coded from the CLI above. In theory, # we should extract the list below from the DataHandler, two lines below this, # but the symbols_filterer has already been tested, so we know that if the CLI # tickers are invalid, the invalid ticker won\u0026#39;t be passed to the data layer. symbols = [\u0026#34;AMD\u0026#34;, \u0026#34;INTC\u0026#34;] bars = HistoricCsvDataHandler(events, data_dir, symbols) buy_hold_portfolio = BuyAndHoldPortfolio(bars, events, datetime.datetime(1960, 1, 1).strftime(\u0026#34;%Y-%m-%d\u0026#34;)) return buy_hold_portfolio class TestBuyAndHoldPortfolio: def test_update_timeindex(self, portfolio_setup): portfolio = portfolio_setup portfolio.bars.update_bars() # triggers a MarketEvent market_event = portfolio.events.get(False) previous_time_index_length = len(portfolio.all_positions) portfolio.update_timeindex(market_event) current_time_index_length = len(portfolio.all_positions) assert current_time_index_length \u0026gt; previous_time_index_length # The actual date is of no interest since it changes based on the assets under # analysis;what we care about is knowing that the time index is updated when # a new market event is captured. def test_update_signal(self, portfolio_setup): portfolio = portfolio_setup portfolio.bars.update_bars() # triggers a MarketEvent strategy = BuyAndHoldStrategy(portfolio.bars, portfolio.events) market_event = portfolio.events.get(False) strategy.calculate_signals(market_event) # triggers a SignalEvent signal_event = portfolio.events.get(False) assert type(signal_event) == SignalEvent portfolio.update_signal(signal_event) # triggers an OrderEvent portfolio.events.get(False) # pop out the SignalEvent first assert type(portfolio.events.get(False)) == OrderEvent def test_update_fill(self, portfolio_setup): portfolio = portfolio_setup portfolio.bars.update_bars() # triggers a MarketEvent strategy = BuyAndHoldStrategy(portfolio.bars, portfolio.events) market_event = portfolio.events.get(False) strategy.calculate_signals(market_event) # triggers a SignalEvent signal_event = portfolio.events.get(False) assert type(signal_event) == SignalEvent portfolio.update_signal(signal_event) # triggers an OrderEvent portfolio.events.get(False) # pop out the SignalEvent first order_event = portfolio.events.get(False) assert type(order_event) == OrderEvent broker = SimulatedExecutionHandler(portfolio.events) broker.execute_order(order_event) fill_event = broker.events.get(False) assert type(fill_event) == FillEvent # We test to see that the current positions and current holdings have changed # after the fill. previous_positions = portfolio.current_positions[fill_event.symbol] previous_holdings = portfolio.current_holdings[fill_event.symbol] portfolio.update_fill(fill_event) assert portfolio.current_positions[fill_event.symbol] != previous_positions assert portfolio.current_holdings[fill_event.symbol] != previous_holdings ","date":"3 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_6/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Portfolio - Part 6","type":"projects"},{"content":"In the previous article we discussed the type of events that the system is prepared to handle. In this article we\u0026rsquo;ll build on that and focus on the Strategy component of the engine.\nIn line with the original series on Quanstart, I\u0026rsquo;ll use the classic Buy \u0026amp; Hold strategy for illustration purposes, but will also explain how to implement a more involved strategy.\nThe buy \u0026amp; hold strategy can be summarised as: buy an asset and don\u0026rsquo;t sell it. Thus, in terms of signals, in such strategy we\u0026rsquo;ll only be generating BUY signals, one for each asset. A more advanced buy \u0026amp; hold strategy can employ filters of all types, i.e. buy only assets that have certain characteristics, but to keep it simple, we\u0026rsquo;ll naively generate BUY signals for all the assets passed from the command line.\nThe final code looks like:\n# trading_engine/strategy.py from abc import ABC, abstractmethod from events import SignalEvent class Strategy(ABC): \u0026#34;\u0026#34;\u0026#34; Strategy is an abstract base class providing an interface for all inherited strategy handling objects. The goal of a derived Strategy class object is to generate Signal objects for particular symbols based on the input Bars (OHLCVI) generated by the DataHandler object. This is designed to work with both live and historical data, since the Strategy object obtains the bar tuples from a queue object. \u0026#34;\u0026#34;\u0026#34; @abstractmethod def calculate_signals(self): \u0026#34;\u0026#34;\u0026#34; Provides the mechanics to calculate the list of signals. \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement calculate_signals()\u0026#34;) class BuyAndHoldStrategy(Strategy): \u0026#34;\u0026#34;\u0026#34; Simple buy \u0026amp; hold strategy: go long on all symbols and never exit a position. It\u0026#39;s a useful benchmark for other strategies. \u0026#34;\u0026#34;\u0026#34; def __init__(self, bars, events): \u0026#34;\u0026#34;\u0026#34; Initialise the buy \u0026amp; hold strategy object. :param bars: the DataHandler object that provides bar information :param events: the Event queue object \u0026#34;\u0026#34;\u0026#34; self.bars = bars self.symbol_list = self.bars.symbol_list self.events = events self.bought = self._calculate_initial_bought() def _calculate_initial_bought(self): \u0026#34;\u0026#34;\u0026#34; Add keys to the dictionary that tracks bought symbols for all symbols in the list and sets them to False \u0026#34;\u0026#34;\u0026#34; bought = {} for s in self.symbol_list: bought[s] = False return bought def calculate_signals(self, event): \u0026#34;\u0026#34;\u0026#34; For a buy \u0026amp; hold strategy the signal is simply a \u0026#39;LONG\u0026#39; or \u0026#39;BUY\u0026#39; for each symbol in the list. :param event: a MarketEvent \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#34;MARKET\u0026#34;: for s in self.symbol_list: bars = self.bars.get_latest_bars(s, N=1) if bars is not None and bars != []: if self.bought[s] is False: # (Symbol, datetime, type = \u0026#34;LONG\u0026#34; || \u0026#34;SHORT\u0026#34;) signal = SignalEvent(bars[0][0], bars[0][1], \u0026#39;LONG\u0026#39;) self.events.put(signal) self.bought[s] = True The key here is the calculate_signal() method. It takes in a MarketEvent, goes through each symbol in the list, generates a BUY SignalEvent for each, and adds them to the event queue.\nIn a more complex strategy, you will very likely also generate SELL signals. For example in a Statistical Arbitrage strategy you will need to buy and sell combinations of assets, almost simultaneously, based on what the statistical model suggests. I have implemented one myself and the pseudo-code should look something like this:\n# [...] class StatArbStrategy(Strategy): \u0026#34;\u0026#34;\u0026#34; Statistical arbitrage strategy based on some model. \u0026#34;\u0026#34;\u0026#34; def __init__(self, bars, events): \u0026#34;\u0026#34;\u0026#34; Initialises the statistical arbitrage strategy. :param bars: the DataHandler object that provides bar information :param events: the Event queue object \u0026#34;\u0026#34;\u0026#34; self.bars = bars self.symbol_list = self.bars.symbol_list self.events = events self.exposure = self._calculate_initial_exposure() def _calculate_initial_exposure(self): \u0026#34;\u0026#34;\u0026#34; Set initial market exposue to 0/False. :return: transacted dict with symbols as keys and values as the type of exposure, i.e. LONG or SHORT -\u0026gt; dict \u0026#34;\u0026#34;\u0026#34; transacted = {} for s in self.symbol_list: transacted[s] = False return transacted def calculate_signals(self, event): \u0026#34;\u0026#34;\u0026#34; Compute the entry and exit signals in line with strategy. :param event: a MarketEvent object \u0026#34;\u0026#34;\u0026#34; if event.type == \u0026#34;MARKET\u0026#34;: for s in self.symbol_list: bars = self.bars.get_latest_bars(s, N=1) if bars is not None and bars != []: # this is a good point to inject the statistical model model = super_duper_money_printing_strat() if model.trade is True: # (Symbol, datetime, type = LONG; SHORT; or EXIT) signal = SignalEvent(bars[0][0], bars[0][1], model.trade_direction) self.events.put(signal) self.exposure[s] = model.trade_direction The key line is:\nmodel = super_duper_money_printing_strat() Which is a placeholder for where you could inject your actual model\u0026rsquo;s parameters.\nThat\u0026rsquo;s it for signals.\nIn the next article we will cover the Portfolio component. It is a central part of the system, so we will spend extra time on it. But as usual, we\u0026rsquo;ll look at tests for the current component before moving on.\nStrategy tests # # trading_engine/tests/test_strategies.py import queue import pytest from data import HistoricCsvDataHandler from strategy import BuyAndHoldStrategy from events import MarketEvent, SignalEvent from utils import data_dir_setup, asset_class_selector, cli_parser @pytest.fixture def strategy_setup(): events = queue.Queue() args = [\u0026#34;--asset_class\u0026#34;, \u0026#34;stocks\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD INTC\u0026#34;] parsed_args = cli_parser(args) asset_class = asset_class_selector(parsed_args) data_dir = data_dir_setup(asset_class) symbols = [\u0026#34;AMD\u0026#34;, \u0026#34;INTC\u0026#34;] bars = HistoricCsvDataHandler(events, data_dir, symbols) return events, bars class TestBuyAndHoldStrategy: def test_calculate_signals(self, strategy_setup): events, bars = strategy_setup bars.update_bars() strategy = BuyAndHoldStrategy(bars, events) market_event = MarketEvent() strategy.calculate_signals(market_event) # triggers a SignalEvent # test that the event queue has been updated with a SignalEvent assert events.empty() is False events.get(False) assert type(events.get(False)) == SignalEvent ","date":"3 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_5/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Strategy - Part 5","type":"projects"},{"content":"In the previous article we covered the data layer, and in this one we will address the different type of events within the engine.\nWhen following an event-driven architecture (EDA), the developer needs to make a decision on what events to capture and which to ignore. This is domain-specific, so there\u0026rsquo;s no hard rule about what events to consider significant. In the context of a backtesting engine, the universe of possible events should be narrowed down to those relevant to any of the core parts of the engine:\ndata handler (data.py) strategy (strategy.py) portfolio (portfolio.py) broker (broker.py) Thus, the events we will be focusing on are:\nMarketEvent \u0026ndash; to simulate data arrival from the market feed SignalEvent \u0026ndash; to generate a signal in line with the strategy logic OrderEvent \u0026ndash; to generate an order FillEvent \u0026ndash; to fill an order We\u0026rsquo;ll dive deeper into each in that order.\n# trading_engine/events.py class Event: \u0026#34;\u0026#34;\u0026#34; Event is the base class providing and interface for all subsequent inherited events. \u0026#34;\u0026#34;\u0026#34; pass class MarketEvent(Event): \u0026#34;\u0026#34;\u0026#34; Handles the event of receiving a new market update with corresponding bars. \u0026#34;\u0026#34;\u0026#34; def __init__(self): \u0026#34;\u0026#34;\u0026#34; Initialises the Market event. :param trade: market event type, either: \u0026#39;LONG\u0026#39;; \u0026#39;SHORT\u0026#39;; or \u0026#39;EXIT\u0026#39; -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; self.type = \u0026#34;MARKET\u0026#34; Not much happening here, so we can carry on to the SignalEvent\n# trading_engine/events.py # [...] class SignalEvent(Event): \u0026#34;\u0026#34;\u0026#34; Handles the event of sending a Signal from a Strategy object. This is received by a Portfolio object and acted upon. \u0026#34;\u0026#34;\u0026#34; def __init__(self, symbol, datetime, signal_type): \u0026#34;\u0026#34;\u0026#34; Initialises the Signal event. :param symbol: the ticker symbol, i.e. \u0026#39;IBM\u0026#39; etc. :param datetime: the timestamp at which the signal was generated :param signal_type: \u0026#34;LONG\u0026#34; or \u0026#34;SHORT\u0026#34; \u0026#34;\u0026#34;\u0026#34; self.type = \u0026#34;SIGNAL\u0026#34; self.symbol = symbol self.datetime = datetime self.signal_type = signal_type This is also fairly straightforward, pass in a bunch of params and assign them to instance variables. It will be clearer what those do when we get to the strategy component.\nMoving on to the OrderEvent,\n# trading_engine/events.py # [...] class OrderEvent(Event): \u0026#34;\u0026#34;\u0026#34; Handles the event of sending an Order to an execution system. The order contains a symbol, a type (market or limit), quantity, and direction \u0026#34;\u0026#34;\u0026#34; def __init__(self, symbol, order_type, quantity, direction): \u0026#34;\u0026#34;\u0026#34; Initialises the order type (MKT or LMT), quantity, and direction \u0026#39;BUY\u0026#39; or \u0026#39;SELL\u0026#39;). :param symbol: symbol of the instrument to trade :param order_type: market \u0026#39;MKT\u0026#39; or limit \u0026#39;LMT\u0026#39; :param quantity: non-negative integer for quantity :param direction: \u0026#39;BUY\u0026#39; or \u0026#39;SELL\u0026#39; \u0026#34;\u0026#34;\u0026#34; self.type = \u0026#39;ORDER\u0026#39; self.symbol = symbol self.order_type = order_type self.quantity = quantity self.direction = direction def print_order(self): \u0026#34;\u0026#34;\u0026#34; Outputs the values within the order (for monitoring purposes). \u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;Order: Symbol={self.symbol}, Type={self.order_type}, \u0026#34; f\u0026#34;Quantity={self.quantity}, Direction={self.direction}\u0026#34;) The print_order() method simply prints the order details to the stdout in the console. I find it helpful when replaying a strategy to see what happens in the terminal.\nFinally, the FillEvent,\n# trading_engine/events.py # [...] class FillEvent(Event): \u0026#34;\u0026#34;\u0026#34; Encapsulates the notion of a filled Order, as returned from a brokerage. Stores the actual quantity filled (which can differ from the ordered amount) and at what price. It also keeps information of the commission cost. \u0026#34;\u0026#34;\u0026#34; def __init__(self, timeindex, symbol, exchange, quantity, direction, fill_cost, commission=None): \u0026#34;\u0026#34;\u0026#34; Initialises the FillEvent object. Sets the symbol, exchange, quantity, direction, cost of fill, and an optional commission. If commission is not provided, the commission calculation will default to Interactive Brokers fees. :param timeindex: the bar-resolution when the order was filled :param symbol: the instrument that was filled :param exchange: the exchange where the order was filled :param quantity: filled quantity :param direction: direction of fill (\u0026#39;BUY\u0026#39; or \u0026#39;SELL\u0026#39;) :param fill_cost: the holdings value in US dollars :param commission: an optional commission if given \u0026#34;\u0026#34;\u0026#34; self.type = \u0026#39;FILL\u0026#39; self.timeindex = timeindex self.symbol = symbol self.exchange = exchange # for now filled and ordered quantity are the same, but in production they might diverge self.filled_quantity = quantity self.ordered_quantity = quantity self.direction = direction self.fill_cost = fill_cost if commission is None: self.commission = self.calculate_ib_commission() else: self.commission = commission def calculate_ib_commission(self): \u0026#34;\u0026#34;\u0026#34; Calculates the fees of trading based on Interactive Brokers fee structure, in USD. This does not include exchange or ECN fees. Reference fees: https://www.interactivebrokers.com/en/index.php?f=commission\u0026amp;p=stocks2 \u0026#34;\u0026#34;\u0026#34; full_cost = 1.3 if self.filled_quantity \u0026lt;= 500: full_cost = max(full_cost, 0.013 * self.filled_quantity) else: full_cost = max(full_cost, 0.008 * self.filled_quantity) if self.fill_cost is not None: full_cost = min(full_cost, 0.5 / 100.0 * self.filled_quantity * self.fill_cost) return full_cost def print_order(self): \u0026#34;\u0026#34;\u0026#34; Outputs the filled order stats -- for bookkeeping purposes. \u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;Filled {self.filled_quantity}/{self.ordered_quantity} units of {self.symbol} {self.direction} order\u0026#34;) As with the OrderEvent I\u0026rsquo;ve added a print_order() to see details of the order that was filled. That\u0026rsquo;s it for the events. In the next article we will go over the Strategy component.\n","date":"3 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_4/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Events - Part 4","type":"projects"},{"content":"As mentioned in the previous article of the series, we will take a closer look at the data layer.\nA snapshot of the data looks like:\nAAPL price ($) Date Open High Low Close Volume OpenInt 0 1984-09-07 0.42388 0.42902 0.41874 0.42388 23220030 0 1 1984-09-10 0.42388 0.42516 0.41366 0.42134 18022532 0 2 1984-09-11 0.42516 0.43668 0.42516 0.42902 42498199 0 3 1984-09-12 0.42902 0.43157 0.41618 0.41618 37125801 0 4 1984-09-13 0.43927 0.44052 0.43927 0.43927 57822062 0 So whichever data you use, will have to follow the tabular/spreadsheet format the engine expects, i.e. aapl.csv would look like this:\nDate,Open,High,Low,Close,Volume,OpenInt 1984-09-07,0.42388,0.42902,0.41874,0.42388,23220030,0 1984-09-10,0.42388,0.42516,0.41366,0.42134,18022532,0 1984-09-11,0.42516,0.43668,0.42516,0.42902,42498199,0 1984-09-12,0.42902,0.43157,0.41618,0.41618,37125801,0 1984-09-13,0.43927,0.44052,0.43927,0.43927,57822062,0 If it doesn\u0026rsquo;t fit your data, then you can adapt this layer at will.\nThe important takeaway is that this is the only part of the engine that should handle data.\nThe final code will look like this:\nDetails # trading_engine/data.py import pandas as pd from abc import ABC, abstractmethod from pathlib import Path from events import MarketEvent from utils import truncate_dfs class DataHandler(ABC): \u0026#34;\u0026#34;\u0026#34; DataHandler is an abstract base class providing an interface for all subsequent inherited data handlers (live and historic). The goal of a derived data handler object is to output a generated set of bars (OHLCVI) for each symbol requested. This will replicate how a live strategy would function as current market data would be sent \u0026#34;down the pipe\u0026#34; (drip feed). An historic and live system will be treated identically in terms of data feed. \u0026#34;\u0026#34;\u0026#34; @abstractmethod def get_latest_bars(self, symbol, N=1): \u0026#34;\u0026#34;\u0026#34; Returns the last N bars from the latest_symbol list, or fewer if less bars are available. \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement get_latest_bars()\u0026#34;) @abstractmethod def update_bars(self): \u0026#34;\u0026#34;\u0026#34; Pushes the latest bar to the latest symbol structure for all symbols in the symbol list \u0026#34;\u0026#34;\u0026#34; raise NotImplementedError(\u0026#34;Should implement update_bars()\u0026#34;) class HistoricCsvDataHandler(DataHandler): \u0026#34;\u0026#34;\u0026#34; HistoricCsvDataHandler is designed to read CSV files for each requested symbol from disk and provide an interface to obtain the \u0026#34;latest\u0026#34; (in the context of historic csv data of course) bar in a manner identical to a live trading interface. \u0026#34;\u0026#34;\u0026#34; def __init__(self, events, csv_dir, symbol_list): \u0026#34;\u0026#34;\u0026#34; Initialises the historic data handler by requesting the location of the CSV files and a list of symbols. It will be assumed that all files are of the form \u0026#39;symbol.csv\u0026#39;, where symbol is a sting in the list. :param events: the Event queue -\u0026gt; Queue object :param csv_dir: directory path to the csv files -\u0026gt; Path or Path-like object :param symbol_list: a list of symbol strings -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; self.events = events self.csv_dir = csv_dir self.symbol_list = symbol_list self.symbol_data = {} self.latest_symbol_data = {} self.continue_backtest = True self._open_convert_csv_files() def _open_convert_csv_files(self): \u0026#34;\u0026#34;\u0026#34; Opens the csv files from the data directory, converting them into pandas DataFrames within a symbol dictionary. \u0026#34;\u0026#34;\u0026#34; # Note: combining the index is particularly useful for mean-reverting strategies, # because it allows graceful handling of missing data comb_index = None for symbol in self.symbol_list: self.symbol_data[symbol] = pd.read_csv( Path.joinpath(self.csv_dir.joinpath(f\u0026#34;{symbol.lower()}.csv\u0026#34;)), header=0, names=[\u0026#34;datetime\u0026#34;, \u0026#34;open\u0026#34;, \u0026#34;high\u0026#34;, \u0026#34;low\u0026#34;, \u0026#34;close\u0026#34;, \u0026#34;volume\u0026#34;, \u0026#34;oi\u0026#34;] ) # combine the index column to pad forward values if comb_index is None: comb_index = self.symbol_data[symbol].index else: comb_index.union(self.symbol_data[symbol].index) self.latest_symbol_data[symbol] = [] # initialise to empty list (for now) # reindex the data frames for symbol in self.symbol_list: self.symbol_data[symbol] = self.symbol_data[symbol].reindex(index=comb_index, method=\u0026#34;pad\u0026#34;).itertuples() def _get_new_bar(self, symbol): \u0026#34;\u0026#34;\u0026#34; Returns the latest bar from the data feed as a tuple of (symbol, datetime, open, high, low, close, volume) :param symbol: symbol to retrieve -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; for bar in self.symbol_data[symbol]: yield tuple([ symbol, bar.datetime, bar.open, bar.high, bar.low, bar.close, bar.volume ]) def get_latest_bars(self, symbol, N=1): \u0026#34;\u0026#34;\u0026#34; Returns the last N bars from the latest_symbol list, or N - K if less are available. :param symbol: symbol to retrieve :param N: non-negative integer indicating number of bars to retrieve \u0026#34;\u0026#34;\u0026#34; try: bars_list = self.latest_symbol_data[symbol] except KeyError as e: print(f\u0026#34;Symbol {symbol} is not available in the historical data set.\u0026#34;) else: return bars_list[-N:] def update_bars(self): \u0026#34;\u0026#34;\u0026#34; Pushes the latest bar to the latest_symbol data structure for all symbols in the list \u0026#34;\u0026#34;\u0026#34; for symbol in self.symbol_list: try: bar = self._get_new_bar(symbol).__next__() except StopIteration: self.continue_backtest = False else: if bar is not None: self.latest_symbol_data[symbol].append(bar) self.events.put(MarketEvent()) Starting from the initialisation method __init__, we have:\nclass HistoricCsvDataHandler(DataHandler): \u0026#34;\u0026#34;\u0026#34; HistoricCsvDataHandler is designed to read CSV files for each requested symbol from disk and provide an interface to obtain the \u0026#34;latest\u0026#34; bar, to simulate a live trading drip feed. \u0026#34;\u0026#34;\u0026#34; def __init__(self, events, csv_dir, symbol_list): \u0026#34;\u0026#34;\u0026#34; Initialise the historic data handler by requesting the location of the CSV files and a list of symbols. It will be assumed that all files are of the form \u0026#39;symbol.csv\u0026#39;, where symbol is a sting in the list. :param events: the Event queue -\u0026gt; Queue object :param csv_dir: directory path to the csv files -\u0026gt; Path or Path-like object :param symbol_list: a list of symbol strings -\u0026gt; str \u0026#34;\u0026#34;\u0026#34; self.events = events self.csv_dir = csv_dir self.symbol_list = symbol_list self.symbol_data = {} self.latest_symbol_data = {} self.continue_backtest = True self._open_convert_csv_files() This method takes in a queue of events, a directory from which ticker data will be retrieved from, and an array of tickers. The params will be assigned to instance attributes with the same name. This naming convention will be followed across the entire engine, wherever possible.\nNext is the _open_convert_csv_files() method:\ndef _open_convert_csv_files(self): \u0026#34;\u0026#34;\u0026#34; Opens the csv files from the data directory, converting them into pandas DataFrames within a symbol dictionary. \u0026#34;\u0026#34;\u0026#34; # Note: combining the index is particularly useful for mean-reverting strategies, # because it allows graceful handling of missing data comb_index = None for symbol in self.symbol_list: self.symbol_data[symbol] = pd.read_csv( Path.joinpath(self.csv_dir.joinpath(f\u0026#34;{symbol.lower()}.csv\u0026#34;)), header=0, names=[\u0026#34;datetime\u0026#34;, \u0026#34;open\u0026#34;, \u0026#34;high\u0026#34;, \u0026#34;low\u0026#34;, \u0026#34;close\u0026#34;, \u0026#34;volume\u0026#34;, \u0026#34;oi\u0026#34;] ) # combine the index column to pad forward values if comb_index is None: comb_index = self.symbol_data[symbol].index else: comb_index.union(self.symbol_data[symbol].index) self.latest_symbol_data[symbol] = [] # initialise to empty list (for now) # reindex the data frames for symbol in self.symbol_list: self.symbol_data[symbol] = self.symbol_data[symbol].reindex(index=comb_index, method=\u0026#34;pad\u0026#34;).itertuples() The above is straightforward: go through each ticker from the list, and retrieve its data, then combine the indices to match time-series of different lengths.\nThe other two important methods are get_latest_bars and update_bars:\ndef get_latest_bars(self, symbol, N=1): \u0026#34;\u0026#34;\u0026#34; Returns the last N bars from the latest_symbol list, or N - K if less are available. :param symbol: symbol to retrieve :param N: non-negative integer indicating number of bars to retrieve \u0026#34;\u0026#34;\u0026#34; try: bars_list = self.latest_symbol_data[symbol] except KeyError as e: print(f\u0026#34;Symbol {symbol} is not available in the historical data set.\u0026#34;) else: return bars_list[-N:] def update_bars(self): \u0026#34;\u0026#34;\u0026#34; Pushes the latest bar to the latest_symbol data structure for all symbols in the list \u0026#34;\u0026#34;\u0026#34; for symbol in self.symbol_list: try: bar = self._get_new_bar(symbol).__next__() except StopIteration: self.continue_backtest = False else: if bar is not None: self.latest_symbol_data[symbol].append(bar) self.events.put(MarketEvent()) The first simply retrieves the latest N bars, and it\u0026rsquo;s set to N = 1 by default, so it\u0026rsquo;ll retrieve one data bar at a time. This is consistent with how a live trading system would receive data. The second method adds the latest bar to the self.latest_symbol_data struct. It internally calls the _get_new_bar method, which I have not explained because it\u0026rsquo;s self-explanatory.\nIf you\u0026rsquo;re lost, refer to the intro post with the driver code in the backtester.py file, to see how update_bars is invoked. get_latest_bars will be relevant later when we discuss the Portfolio and the Strategy components.\nIn the next article we will go over the events layer, but first we\u0026rsquo;ll write tests for the code of the data layer we\u0026rsquo;ve discussed so far.\nData tests # / ├── tests │ ├── __init__.py │ └── test_utils.py │ └── test_data_handler.py \u0026lt;--- new file # trading_engine/tests/test_data_handler.py import queue import pytest from data import HistoricCsvDataHandler from events import MarketEvent from utils import data_dir_setup, asset_class_selector, cli_parser @pytest.fixture def stocks_setup(): events = queue.Queue() symbols = [\u0026#34;AMD\u0026#34;, \u0026#34;ZVV\u0026#34;] args = [\u0026#39;--asset_class\u0026#39;, \u0026#39;stocks\u0026#39;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD ZVV\u0026#34;] parsed_args = cli_parser(args) asset_class = asset_class_selector(parsed_args) data_dir = data_dir_setup(asset_class) return events, data_dir, symbols def test_update_bars(stocks_setup): events, data_dir, symbols = stocks_setup bars = HistoricCsvDataHandler(events, data_dir, symbols) # test two things: # 1. that a bar data for a symbol is returned # 2. that a MarketEvent is added to the event queue bars.update_bars() first_symbol_data = bars.latest_symbol_data[symbols[0]] second_symbol_data = bars.latest_symbol_data[symbols[1]] assert first_symbol_data is not None assert second_symbol_data is not None assert events.empty() is False assert events.empty() is False assert type(events.get(False)) == MarketEvent def test_update_bars_when_backtest_data_is_exhausted(stocks_setup): events, data_dir, symbols = stocks_setup bars = HistoricCsvDataHandler(events, data_dir, symbols[1:]) # stock \u0026#34;ZVV\u0026#34; has only 5 observations in my dataset, so when we call # update_bars() the 6th time, it\u0026#39;ll trigger a StopIteration error, # and set the continue_backest flag to False. bars.update_bars() bars.update_bars() bars.update_bars() bars.update_bars() bars.update_bars() bars.update_bars() assert bars.continue_backtest == False Notice the code comment in the last test case. Doing that is ok, but it closely ties the data from the test environment to the application code, but we can do better. In a production setting you would create data specific to the test environment, so the two can run in isolation. For our specific case we would then create mock or stub data of AMD and ZVV .csv files.\n","date":"2 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_3/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Data - Part 3","type":"projects"},{"content":"As mentioned in the previous article, we will cover at a high level the code in backtester.py.\nSetup # At the top we have the import statements,\n# trading_engine/backtester.py import datetime import queue from data import HistoricCsvDataHandler from strategy import BuyAndHoldStrategy, StatArbStrategy from portfolio import BuyAndHoldPortfolio from broker import SimulatedExecutionHandler from utils import * In the actual execution block,\nif __name__ == \u0026#34;__main__\u0026#34;: parsed_args = cli_parser() asset_class = asset_class_selector(parsed_args) data_dir = data_dir_setup(asset_class) # rest of code [...] The first three lines that deal with parsing the stocks inserted in the command line, identifying the asset class (defaults to equities), and setting up the data directory to read the .csv files from (in the case of the CSV Data Handler). These functions are defined in utils.py as such:\nDetails # trading_engine/utils.py def cli_parser(args=None): \u0026#34;\u0026#34;\u0026#34; Parses the asset class from the command line, if any. :return: Parsed arguments accessible with dot notation -\u0026gt; Namespace-like object \u0026#34;\u0026#34;\u0026#34; parser = argparse.ArgumentParser(description=\u0026#34;*** Event-driven Backtester ***\u0026#34;) parser.add_argument(\u0026#34;--asset_class\u0026#34;, type=str, help=\u0026#34;Asset type, i.e. \u0026#39;stocks\u0026#39;, \u0026#39;commodities\u0026#39;, \u0026#39;currencies\u0026#39;\u0026#34;, default=\u0026#34;stocks\u0026#34;) parser.add_argument(\u0026#34;--tickers\u0026#34;, type=str, help=\u0026#34;Instrument\u0026#39;s ticker, i.e. AAPL, etc.\u0026#34;, nargs=\u0026#39;*\u0026#39;, action=\u0026#39;append\u0026#39;) allowed_assets = [\u0026#34;stocks\u0026#34;, \u0026#34;equities\u0026#34;] asset_class = parser.parse_args(args).asset_class.lower() if asset_class not in allowed_assets: # raises a SystemExit error parser.error(f\u0026#34;Asset class \u0026#39;{asset_class}\u0026#39; not currently supported.\\n\u0026#34; f\u0026#34;Supported types are: stocks for now (more to come in due time\u0026#34;) if parser.parse_args(args).tickers is None: parser.error(\u0026#34;No ticker provided -- please provide at least one valid ticker\\n\u0026#34; \u0026#34;You can add more tickers separated by a space, i.e. AAPL GOOGL, etc.\u0026#34;) return parser.parse_args(args) def asset_class_selector(parsed_args): asset_class = parsed_args.asset_class if asset_class == \u0026#34;equities\u0026#34;: asset_class = \u0026#34;stocks\u0026#34; return asset_class def data_dir_setup(asset_class): \u0026#34;\u0026#34;\u0026#34; Sets the data source directory where the Data Handler will get data from. :return: source directory the Data handler will use -\u0026gt; Path or Path-like object \u0026#34;\u0026#34;\u0026#34; source_dir = Path.cwd().joinpath(\u0026#34;datasets\u0026#34;) if asset_class == \u0026#34;stocks\u0026#34; or asset_class == \u0026#34;etfs\u0026#34; : assets_dir = source_dir.joinpath(\u0026#34;equities\u0026#34;).joinpath(asset_class) else: assets_dir = source_dir.joinpath(asset_class) return assets_dir To make sense of the data_dir_setup function, it helps to see the directory structure it expects:\n/ ├── datasets │ ├── bonds │ ├── commodities │ ├── currencies │ └── equities │ ├── etfs │ └── stocks We\u0026rsquo;ll focus on the stocks folder for the rest of the series, but the above will work with other asset types, if those other directories are populated with relevant .csv or .txt data, in the format \u0026lt;ticker\u0026gt;.csv.\nif __name__ == \u0026#34;__main__\u0026#34;: # [...] # main, and only, event queue (FIFO) events = queue.Queue() # input symbols symbols = symbols_filterer(parsed_args.tickers[0], data_dir) # engine components bars = HistoricCsvDataHandler(events, data_dir, symbols) buy_hold_strategy = BuyAndHoldStrategy(bars, events) buy_hold_portfolio = BuyAndHoldPortfolio(bars, events, datetime.datetime(1960, 1, 1).strftime(\u0026#34;%Y-%m-%d\u0026#34;)) broker = SimulatedExecutionHandler(events) In the above we define a Queue object. This is from the standard library and internally handles synchronisation by blocking/locking out competing threads. This queue object will be passed around to each of the engine components so they can independently add events to the queue.\nNext is the symbols_filterer which is another function defined in utils.py that takes the tickers passed by the user from the command line, and filters out tickers that are not present in the data_dir:\n# trading_engine/utils.py [...] def symbols_filterer(tickers, datasource): \u0026#34;\u0026#34;\u0026#34; Checks if the symbols provided are available in the datasource, and return a filtered list of only the valid ones. Valid tickers being ones that are available in the local datasource. Currently only supports datasource as a local directory. :param tickers: list of symbols -\u0026gt; List[str] :param datasource: repository where data is to be retrieved from -\u0026gt; Path-like object | Iterable :return: filtered list of the valid tickers [\u0026#39;AAPL\u0026#39;, \u0026#39;GOOGL\u0026#39;] -\u0026gt; List[str] \u0026#34;\u0026#34;\u0026#34; filtered_list = [] for ticker_file in datasource.iterdir(): ticker = ticker_file.stem.split(\u0026#34;.\u0026#34;)[0].upper() if ticker in tickers: filtered_list.append(ticker) # none of the tickers the user provided are available or valid; provide a safe default if not filtered_list: print(\u0026#34;None of the tickers provided are valid or available.\\nPlease Try again with others.\\n\u0026#34; \u0026#34;Defaulting to \u0026#39;AMD\u0026#39;\\n\u0026#34;) filtered_list.append(\u0026#39;AMD\u0026#39;) return filtered_list So you might run the following in the command line:\n$ python backtester.py --tickers AAPL MSFT NONSENSE\nbut only Apple and Microsoft will be considered since NONSENSE is not a ticker available in the local datasource.\nThe last part shows the engine components themselves.\nExecution # if __name__ == \u0026#34;__main__\u0026#34;: # [...] # main execution loop while True: if bars.continue_backtest: bars.update_bars() else: print(\u0026#34;End of backtesting...\u0026#34;) buy_hold_portfolio.create_equity_curve_dataframe() print(\u0026#34;\\n **** Portfolio statistics **** \\n\u0026#34;) for stat in buy_hold_portfolio.output_summary_stats(): print(stat) break while True: try: event = events.get(False) except queue.Empty: break else: if event is not None: if event.type == \u0026#34;MARKET\u0026#34;: buy_hold_strategy.calculate_signals(event) buy_hold_portfolio.update_timeindex(event) elif event.type == \u0026#34;SIGNAL\u0026#34;: buy_hold_portfolio.update_signal(event) elif event.type == \u0026#34;ORDER\u0026#34;: broker.execute_order(event) elif event.type == \u0026#34;FILL\u0026#34;: buy_hold_portfolio.update_fill(event) The outer loop runs till there\u0026rsquo;s no more backtesting data. The inner loop runs infinitely on the condition that the outer one does too. In a backtesting environment the outer loop will have an end, but in a live-trading environment, the outer loop will also run infinitely or with a very long-lived condition according to the trading/investment strategy.\nWhile the bars.continue_backtest condition is true, bars.update_bars() will add a MarketEvent to the queue when a new data bar \u0026ldquo;arrives\u0026rdquo; from the data feed (to simulate how a market feed \u0026ldquo;drips\u0026rdquo; data progressively). Said MarketEvent will trigger the chain of events in the else condition of the inner loop.\nIn the next article we will work on the data layer in more detail, but before that we will look at tests for the utility functions in utils.py mentioned earlier. We don\u0026rsquo;t need to do this now, but it helps get into the frame of mind of writing tests for code as you\u0026rsquo;re working on it.\nTesting the utility functions in the Setup section # I\u0026rsquo;ll use pytest as test runner. It looks for the tests folder from the root of the project, thus:\n/ ├── tests │ ├── __init__.py │ └── test_utils.py The convention is to name the test file after the application code it tests, so for utils.py you should have a test file named test_utils.py:\n# trading_engine/tests/test_utils.py import pytest from types import SimpleNamespace from utils import * @pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#39;--tickers\u0026#39;, \u0026#39;AMD\u0026#39;], ]) def test_asset_class_parser_default(args): parser = cli_parser(args) # no asset_class arg provided assert parser.asset_class == \u0026#39;stocks\u0026#39; The test above checks that the backtester defaults to stocks as asset class when the arg --asset_class is not provided in the command line.\nThe idea of automated tests is that they should be descriptive, have a clear scope, and should run fast. They provide a sanity check and improve developer confidence because you can fix bugs or develop new features with the assurance that if something breaks you can look at the test suite to narrow down what is broken or reveal gaps in the application logic or test coverage.\nNow that we\u0026rsquo;ve tested the default condition of the Command Line Interface (CLI) parser, we can test two other paths: one where we provide a supported asset class, and another where the asset class is not supported, i.e. any other asset class that is not stocks:\n@pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#34;--asset_class\u0026#34;, \u0026#34;stocks\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD\u0026#34;], [\u0026#34;--asset_class\u0026#34;, \u0026#34;equities\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD\u0026#34;], ]) def test_asset_class_parser_with_supported_assets(args): parser = cli_parser(args) assert parser.asset_class == args[1] @pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#39;--asset_class\u0026#39;, \u0026#39;stonks\u0026#39;], [\u0026#39;--asset_class\u0026#39;, \u0026#39;super stonks\u0026#39;], [\u0026#39;--asset_class\u0026#39;, \u0026#39;currencies\u0026#39;], [\u0026#39;--asset_class\u0026#39;, \u0026#39;commodities\u0026#39;] ]) def test_asset_class_parser_with_unsupported_assets(args): with pytest.raises(SystemExit): parser = cli_parser(args) And so forth with other functions within utils.py. By the end of the exercise you should have something like this:\nDetails # trading_engine/tests/test_utils.py import pytest from types import SimpleNamespace from utils import * @pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#39;--tickers\u0026#39;, \u0026#39;AMD\u0026#39;], ]) def test_asset_class_parser_default(args): parser = cli_parser(args) # no asset_class arg provided assert parser.asset_class == \u0026#39;stocks\u0026#39; @pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#34;--asset_class\u0026#34;, \u0026#34;stocks\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD\u0026#34;], [\u0026#34;--asset_class\u0026#34;, \u0026#34;equities\u0026#34;, \u0026#34;--ticker\u0026#34;, \u0026#34;AMD\u0026#34;], ]) def test_asset_class_parser_with_supported_assets(args): parser = cli_parser(args) assert parser.asset_class == args[1] @pytest.mark.parametrize(\u0026#39;args\u0026#39;, [ [\u0026#39;--asset_class\u0026#39;, \u0026#39;stonks\u0026#39;], [\u0026#39;--asset_class\u0026#39;, \u0026#39;currencies\u0026#39;], [\u0026#39;--asset_class\u0026#39;, \u0026#39;commodities\u0026#39;] ]) def test_asset_class_parser_with_unsupported_assets(args): with pytest.raises(SystemExit): parser = cli_parser(args) @pytest.mark.parametrize(\u0026#39;parsed_args\u0026#39;, [ SimpleNamespace({\u0026#39;asset_class\u0026#39;: \u0026#39;stonks\u0026#39;}), SimpleNamespace({\u0026#39;asset_class\u0026#39;: \u0026#39;options\u0026#39;}), SimpleNamespace({\u0026#39;asset_class\u0026#39;: \u0026#39;bonds\u0026#39;}), ]) def test_asset_class_selector(parsed_args): asset_class = asset_class_selector(parsed_args) assert parsed_args.asset_class == asset_class @pytest.mark.parametrize(\u0026#39;asset_class\u0026#39;, [ \u0026#39;stocks\u0026#39;, \u0026#39;etfs\u0026#39;, ]) def test_data_dir_setup_equities(asset_class): asset_dir = data_dir_setup(asset_class) assert asset_dir.stem == asset_class assert asset_dir.parent.stem == \u0026#34;equities\u0026#34; @pytest.mark.parametrize(\u0026#39;asset_class\u0026#39;, [ \u0026#39;currencies\u0026#39;, \u0026#39;commodities\u0026#39;, \u0026#39;bonds\u0026#39;, \u0026#39;options\u0026#39;, ]) def test_data_dir_setup_non_equities(asset_class): asset_dir = data_dir_setup(asset_class) assert asset_dir.stem == asset_class assert asset_dir.parent.stem == \u0026#34;datasets\u0026#34; def test_symbols_filterer_with_unavailable_ticker(): tickers = [\u0026#39;AMD\u0026#39;, \u0026#39;INTC\u0026#39;, \u0026#39;INVALID_TICKER\u0026#39;] datasource = data_dir_setup(\u0026#34;stocks\u0026#34;) symbols_list = symbols_filterer(tickers, datasource) assert \u0026#34;INVALID_TICKER\u0026#34; not in symbols_list def test_symbols_filterer_with_available_ticker(): tickers = [\u0026#39;AMD\u0026#39;, \u0026#39;INTC\u0026#39;, \u0026#39;MSFT\u0026#39;] datasource = data_dir_setup(\u0026#34;stocks\u0026#34;) symbols_list = symbols_filterer(tickers, datasource) assert \u0026#34;MSFT\u0026#34; in symbols_list ","date":"2 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_2/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Overview - Part 2","type":"projects"},{"content":"This post is part of a series that will cover how to build an event-driven backtesting engine. I\u0026rsquo;ve used Python, but you can adapt the concepts to any language.\nThis project is inspired from this series on Quantstart, with my own additions and refinements. As we\u0026rsquo;re going over each of the building blocks of the engine, I\u0026rsquo;ll also show you how to write tests to cover the features.\nBy the end of this series you should be able to:\nreproduce something similar in your language of choice, following an event-driven architecture adapt the backtester to a live trading environment or a simulated one with minimal changes Before diving into the code, here\u0026rsquo;s a schematic of how events flow in the engine:\nflowchart TD A(Market feed from broker or data provider) --\u003e B(Data management layer) B--\u003e D(Event Manager) D--\u003eE(Non-market event) D--\u003eF(Market event) F--\u003eG(Process trading signal) G--\u003e|Trade|H[No] G--\u003e|Trade|I[Yes] I--\u003eJ(Open new position) J--\u003eK(Order manager) K--\u003eL(Calculate optimal position size and risk level) L--\u003eM(Send order to broker) M--\u003eN(Book new order into portfolio) N--\u003eO(Portfolio: monitor positions, calculate risk, calculate PnL) O--\u003eP(Risk above threshold) O--\u003eQ(Risk below threshold) P--\u003eR(Close position) Q--\u003eS(Keep position open)--\u003eO In terms of code organisation, I\u0026rsquo;ve arranged each significant part from the diagram above into its own file, i.e data.py for the data layer, events.py for the events, etc.\nFor the impatient, the final code looks like this, backtester.py:\nDetails # trading_engine/backtester.py import datetime import queue from data import HistoricCsvDataHandler from strategy import BuyAndHoldStrategy, StatArbStrategy from portfolio import BuyAndHoldPortfolio from broker import SimulatedExecutionHandler from utils import * if __name__ == \u0026#34;__main__\u0026#34;: parsed_args = cli_parser() asset_class = asset_class_selector(parsed_args) data_dir = data_dir_setup(asset_class) # main, and only, event queue (FIFO) events = queue.Queue() # input symbols symbols = symbols_filterer(parsed_args.tickers[0], data_dir) # engine components bars = HistoricCsvDataHandler(events, data_dir, symbols) buy_hold_strategy = BuyAndHoldStrategy(bars, events) buy_hold_portfolio = BuyAndHoldPortfolio(bars, events, datetime.datetime(1960, 1, 1).strftime(\u0026#34;%Y-%m-%d\u0026#34;)) broker = SimulatedExecutionHandler(events) # main execution loop while True: if bars.continue_backtest: bars.update_bars() else: print(\u0026#34;End of backtesting...\u0026#34;) buy_hold_portfolio.create_equity_curve_dataframe() print(\u0026#34;\\n **** Portfolio statistics **** \\n\u0026#34;) for stat in buy_hold_portfolio.output_summary_stats(): print(stat) break while True: try: event = events.get(False) except queue.Empty: break else: if event is not None: if event.type == \u0026#34;MARKET\u0026#34;: buy_hold_strategy.calculate_signals(event) buy_hold_portfolio.update_timeindex(event) elif event.type == \u0026#34;SIGNAL\u0026#34;: buy_hold_portfolio.update_signal(event) elif event.type == \u0026#34;ORDER\u0026#34;: broker.execute_order(event) elif event.type == \u0026#34;FILL\u0026#34;: buy_hold_portfolio.update_fill(event) And you would run it with:\n$ python backtester.py --ticker AAPL\nto run a backtest on Apple\u0026rsquo;s stock.\nFor a portfolio of multiple stocks you can run:\n$ python backtester.py --tickers AAPL MSFT AMD INTC\nHowever, there is a benefit to following each part of the series to better understand how it all comes together in the snippet above.\nIn the next article we will briefly cover at a high level how each parts fits into the whole.\n","date":"1 September 2025","externalUrl":null,"permalink":"/projects/backtesting_engine_1/","section":"Projects","summary":"","title":"Event-driven Python backtesting engine - Intro - Part 1","type":"projects"},{"content":" 1. Data # Tickers:\nBitcoin (BTC-USD, or BTC in short) MARA RIOT CLSK Type: OHLCV data (Open, High, Low, Close, Volume).\nTimeframe: from 02 January 2020 to 23 May 2024.\nFrequency: daily observations.\nN.B.: BTC trades 24/7 while the crypto stocks follow regular market hours, so no weekends. This means that the data for Bitcoin needs to be adjusted to not take into account weekends. I have omitted the code used for the pre-processing phase, to focus primarily on the analysis itself, but I can make it available upon request.\n2. Analysis scope # Primary analysis scope: investigate the relationship between closing price of Bitcoin and the closing price of the three crypto mining stocks. Additionally, repeat the exercise for with the (OHLC) price average of the three stocks.\nSecondary analysis scope: analyse the effect of Bitcoin up days on the three stocks. Similarly, analyse the effect of Bitcoin down days on the three stocks.\nN.B.: Up days mean that the Close price was higher than the Open price for that day. Vice versa, down days are the ones where the Close price was lower than the Open price. Based on the interval under analysis, there is no observation where Bitcoin was flat, it was either Up (green) or Down (red) days.\n3. Analysis # For the primary analysis, standard line and scatter plots were implemented to get a feel of the data. In Fig. 1. you can see the time series over the entire timeframe for BTC. In Fig. 2 you can see the same for the three stocks. From Figure 1. we see that BTC doesn’t really follow the same patterns as the three crypto mining stocks, while the three stocks move very closely together.\nPotential scope for more research: not related to the scope of the current tasks, but the closeness of the three stocks could perhaps be modelled under a Vector Autoregressive (VAR) model, and potentially exploit anomalies via pairs or trio trading.\nFigure 1. BTC\nFigure 2. MARA | RIOT | CLSK\nFollowing, the scatter plots in Fig. 3; Fig. 4; and Fig. 5, show a positive and weak correlation between BTC and the stocks. From the graphs we notice that all three stocks are positively correlated, yet the correlation is not strong. Repeating the exercise with the average of Open, High, Low, and Close price yields nearly identical results.\nFigure 3. BTC MARA correlation\nFigure 4. BTC RIOT correlation\nFigure 5. BTC CLSK correlation\nThe weak correlation is validated in the secondary analysis where the directional impact of BTC is analysed against the crypto stocks. Before delving into the secondary analysis, I need to note that unlike BTC, the three stocks occasionally show flat days. A flat day is a day when the Open price is equal to the Close price. This will be relevant in explaining why when I compute the statistics of up/down days of the three stocks, up + down percentage doesn\u0026rsquo;t equal 100% but slightly less.\nTo meet the goals of the secondary analysis, I opted for a simple scoring mechanism that checks on day \\( 𝑡 \\) if Bitcoin is \\( 𝑢𝑝 (𝐶𝑙𝑜𝑠𝑒\u003e𝑂𝑝𝑒𝑛) \\): check each of the stocks and note if it’s \\( 𝑢𝑝 \\) or \\( 𝑑𝑜𝑤𝑛 (𝐶𝑙𝑜𝑠𝑒\u003c𝑂𝑝𝑒𝑛) \\). If it’s not \\( up \\) or \\( down \\), then it’s \\( 𝑓𝑙𝑎𝑡 (𝑂𝑝𝑒𝑛=𝐶𝑙𝑜𝑠𝑒) \\).\nThe summary statistics have been collected in Table 1. and Table 2.\nBitcoin up days (total: 565)\nUp days (%) Down days (%) Flat (%) MARA 57.52 40.71 1.77 RIOT 59.65 40 0.35 CLSK 54.34 44.6 1.06 Table 1. Bitcoin up days\nBitcoin down days (total: 541)\nUp days (%) Down days (%) Flat (%) MARA 34.57 64.51 0.92 RIOT 31.79 66.36 1.85 CLSK 32.9 65.43 1.67 Table 2. Bitcoin down days\n4. Conclusions and insights # From Table 1. we see that the three stocks will generally follow the same direction when BTC is up. This matches what is shown in the scatter graphs, with RIOT showing the highest percentage of up days among the three. This could be interpreted as a weak BUY/LONG signal in a trading strategy.\nFrom Table 2. we see that the three stocks will generally follow the same direction when BTC is down. Similarly to Table 1., RIOT shows the highest percentage of down days among the three stocks. This could be interpreted as a weak SELL/SHORT signal.\nFrom the two tables above one could make the argument that when BTC is up, the three stocks are very likely going to be up but not very strongly, or in other words, there is also an abundance of days when the stocks tanked. This makes sense because there are other factors that enter stock price. On the other hand, when BTC is down, in relative terms to the up days, there’s a stronger argument to go short on the stocks because of the wider gap between Down days (%) and Up days (%).\nWhat about other cryptos? # You can reach out via email here or Linkedin.\nIf you found this analysis interesting feel free to share on any of the social media links below.\n","date":"1 October 2024","externalUrl":null,"permalink":"/research/btc_mara_riot_clsk/","section":"Research","summary":"","title":"BTC MARA RIOT CLSK correlation analysis","type":"research"},{"content":"","date":"1 October 2024","externalUrl":null,"permalink":"/research/","section":"Research","summary":"","title":"Research","type":"research"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/cointegration/","section":"Tags","summary":"","title":"Cointegration","type":"tags"},{"content":" For an introduction on Cointegration, read the Wikipedia entry. In the rest of the post, I will assume you know what cointegration means. I will, of course, provide context where needed, but this is an intermediate read, and the assumption is that you\u0026rsquo;re familiar with Time Series Analysis.\nThe primary focus here is to show how to correctly apply the cointegration framework to real data. The secondary focus is to apply this framework to pairs trading. The rest of this post will focus on the data considerations and statistical modelling.\n1. Data # Tickers: EUR/CHF, EUR/GBP, GBP/CHF\nType:\nSpot market: Bid-Ask Close prices Timeframe: 2009 - 2019\nFrequency: daily\nTotal observations: ~2870\nThe data is widely available from other sources, but I can provide it upon request (contact links at the end of the article).\n2. Analysis scope # Intuition: cointegration establishes whether two or more variables have a statistically significant correlation in the long term. One of the main points of this framework is to avoid the issue of spurious regressions.\nThe three tickers under analysis, are the major currency pairs of the countries within the European Economic Area (EEA). The expectation here is that these pairs are \u0026ldquo;linked\u0026rdquo; in the long-term because they are a proxy for the economies of the underlying countries. These countries are also closely linked to one another via trade, geography, culture, and history (working hours, holidays, freedom of movement, etc.).\nThe scope of the analysis will show if this thesis is validated or not by the data.\n3. Analysis # To correctly model this framework to the data, we need to go through the following steps:\npick a significance level for the statistical tests, e.g., 1%, 5%, 10%, etc. I selected \\( \\alpha=0.05 \\).\nperform stationarity tests on the variables to make sure that they are non-stationary in levels, or integrated of order 1, or \\( I(1) \\). All variables need to be integrated of the same order.\nselect a Vector Autoregression \\( (VAR) \\) model and choose an appropriate lag order \\( p \\). The \\( p \\) can be selected with information criteria like Akaike (AIC), Bayesian (BIC), or Hannan-Quinn (HQC), or other underlying theory or belief of the analyst.\nestimate the \\( VAR(p) \\) model in step 2. and test for the whiteness of residuals.\nif the errors are white noise, then the selected \\( VAR(p) \\) correctly describes the data.\nperform Johansen cointegration test on a Vector Error Correction Model \\( (VECM) \\) of order \\( p -1 \\) to establish the number of cointegrating relationships between input variables. For three variables, the outcome of the test can be any of the following:\n0 -\u0026gt; variables are integrated but not cointegrated; 1 -\u0026gt; 1 cointegrating relationship -\u0026gt; VECM is an appropriate model; (best outcome) 2 -\u0026gt; 2 cointegrating relationships -\u0026gt; VECM is an appropriate model; (second best outcome) 3 -\u0026gt; no cointegration, the variables follow different systematic factors -\u0026gt; VECM is not an appropriate model. In general, for \\( m \\) variables, we want \\( r = m - 1 \\geq 1 \\), for cointegration to be present. Where \\( r \\) represents the number of cointegrating relationships, which is also the rank of the long-run impact matrix, \\( \\beta \\), in the following equation\n$$ Π=αβ' \\tag{1} $$where, \\(Π \\) is a \\( m\\ x\\ m \\) matrix. \\( Π \\) comes from the full VECM model below,\n$$ \\Delta X_t = c + \\Pi X_{t-1} + \\sum_{i=1}^{p-1} \\delta_i \\Delta X_{t-i} + \\epsilon_t \\tag{2} $$where, \\( X_t \\) is a vector of \\( m \\) variables, \\(c \\) is a vector of constants, \\( \\delta_i \\) are \\( m\\ x\\ m \\) matrices of coefficients, and \\( \\epsilon_t \\) is a multivariate white noise process.\nif cointegration is found in the previous step, we can estimate the \\( VECM(p -1) \\) model with cointegration rank \\( r \\). Once we\u0026rsquo;ve fit the model to the data, we can analyse the results and draw conclusions. In this case the initial thesis was that EUR/CHF, EUR/GBP, and GBP/CHF are cointegrated.\n4. Results # I used Python\u0026rsquo;s statsmodels to implement the steps in section 3., but if you use a different software the results may vary. Also, from equation (2) you can see I used a constant term, but not all VECMs need one. It makes sense here because the exchange rates of the major European currencies are not going to drop to zero, yet I could not, a priori, establish what this constant term was, and so also had to estimate it.\nIf equities were under analysis, the constant term could\u0026rsquo;ve been omitted, depending on the actual ticker/symbol. The results I obtained required that assumption on my part \u0026ndash; although they were formed based on a prior analysis of the data. In general, The smallest amount of assumptions the better.\nThe results from the Johansen test supports the existence of \\( 1 \\) cointegrating relationship between the three currency pairs. My thesis has been validated by the data. From Table 1, we can extract the coefficients for the cointegrating equation in formula (3).\nCointegration relations for loading-coefficients coef std err z P\u0026gt;|z| [0.025 0.975] Beta matrix rank beta.1 1.0000 0 0 0.000 1.000 1.000 1 beta.2 -1.4658 0.012 -124.293 0.000 -1.489 -1.443 beta.3 -0.8768 0.004 -201.595 0.000 -0.885 -0.868 const 1.2860 0.013 100.911 0.000 1.261 1.311 Table 1. Cointegrating relationship\n$$ S_t = 1.2860 + EUR/CHF_t -1.4658\\ EUR/GBP_t -0.8768\\ GBP/CHF_t \\tag{3} $$ According to the theory, series \\( S_t \\) is stationary, or \\( S_t \\sim I(0) \\). There are different ways to test that,\nrun stationarity tests as suggested in the previous section; plot series \\( S_t \\); plot the residuals of \\( VECM(p - 1) \\). I will go for option 2. because of simplicity:\nBut for good measure I took another stationarity test and confirmed it. By visual inspection, the spikes might seem excessive or could lead to believe it\u0026rsquo;s non-stationary, but if you look at the magnitude of the values on the Y-axis you\u0026rsquo;ll notice even the \u0026ldquo;extreme\u0026rdquo; values are really not extreme.\n5. Concluding remarks # My expectations have been matched by the data because the results show that there\u0026rsquo;s cointegration in the major European currencies from 2009 to 2019. My focus was not to explain this relationship but simply to test whether it exists or not. I\u0026rsquo;ve also managed to show how to correctly implement the cointegration framework to real data and extract the most important parts for the application to pairs trading, or trio trading in this case. I\u0026rsquo;m hoping this would help you in implementing your money-printing trading strategy. I\u0026rsquo;m not asking for much, just that you remember me when you\u0026rsquo;re on your megayacht.\nWhat about other pairs or trios? # I only covered those tickers because I\u0026rsquo;m familiar with them and had a good reason to believe they were correlated. You can apply this framework to other variables, for purposes outside pairs trading. VAR and VECM models have applications outside Econ/Finance.\nIf you found this analysis interesting feel free to share on the social media links below. For anything else you can also reach out via email here or Linkedin.\n","date":"13 June 2024","externalUrl":null,"permalink":"/research/cointegration_analysis/","section":"Research","summary":"","title":"Cointegration analysis case study: Pairs trading","type":"research"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/forex/","section":"Tags","summary":"","title":"Forex","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/fx/","section":"Tags","summary":"","title":"Fx","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/pairs-trading/","section":"Tags","summary":"","title":"Pairs Trading","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/statistical-modelling/","section":"Tags","summary":"","title":"Statistical Modelling","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/statistics/","section":"Tags","summary":"","title":"Statistics","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/trading/","section":"Tags","summary":"","title":"Trading","type":"tags"},{"content":"","date":"13 June 2024","externalUrl":null,"permalink":"/tags/trading-signals/","section":"Tags","summary":"","title":"Trading Signals","type":"tags"},{"content":"Follow me on Twitter/X @livyathan_io\nFor any enquiries you can email me at: here\nYou can also contact me on Linkedin\n","date":"6 May 2024","externalUrl":null,"permalink":"/contact/","section":"Home","summary":"","title":"Contact","type":"page"},{"content":"","date":"6 May 2024","externalUrl":null,"permalink":"/tags/contact-us/","section":"Tags","summary":"","title":"Contact Us","type":"tags"},{"content":"","date":"3 September 2023","externalUrl":null,"permalink":"/tags/equities/","section":"Tags","summary":"","title":"Equities","type":"tags"},{"content":"","date":"3 September 2023","externalUrl":null,"permalink":"/tags/investing/","section":"Tags","summary":"","title":"Investing","type":"tags"},{"content":"","date":"3 September 2023","externalUrl":null,"permalink":"/tags/modelling/","section":"Tags","summary":"","title":"Modelling","type":"tags"},{"content":"","date":"3 September 2023","externalUrl":null,"permalink":"/tags/options-pricing/","section":"Tags","summary":"","title":"Options Pricing","type":"tags"},{"content":" Have you ever wondered why almost every Finance textbook and university lecturer, when it comes to discussing stock returns, starts with the assumption that stock returns follow a normal distribution? Me too!\nThen after starting from that assumption, said authors and lecturers, will normally carry on building other assumptions on top of that first one, without explaining or showing why that\u0026rsquo;s the case.\nThe Black-Scholes model (BS), which is a staple in option pricing formulas, also relies on that assumption.\nI\u0026rsquo;m inquisitive by nature so decided to get to the bottom of it, and test if that assumption is evidence-based or not.\nDataset and testing # The normality test I picked is the Kolmogorov–Smirnov test because it works well with large data sets. The test was performed at \\(a = 0.01 \\) significance level. The dataset is made of over 7,000 stock symbols from the US market, observed daily. Each series varies in length, based on when the company went public. Some will have \u0026ldquo;only\u0026rdquo; 5 years worth of daily data, others 30 years. The dataset is large enough for statistical inference.\nThe dataset is available upon request.\nOnly ~100 stocks out of 7000+ show normal log-returns, so it\u0026rsquo;s safe to conclude that the assumption in the Black-Scholes model is not validated by reality, and thus by extension, the other claim that stock prices follow a log-normal distribution is also invalid.\nThe formula for log-returns is:\n$$ R_t = ln( \\frac {P_t} {P_{t-1}} ), $$where \\( t \\) denotes the frequency of the observations; \\( P_t \\) the price of the asset at time \\( t \\); and \\( P_{t-1} \\) the price of the asset at the previous point in time.\nThe Python driver code is:\n# computing/log_returns_normality.py import numpy as np import pandas as pd from pathlib import Path from scipy.stats import kstest # path containing the individual stocks OHLCOV data in .csv format dataset_dir = Path.cwd() / \u0026#34;datasets\u0026#34; / \u0026#34;US_equities_OHLCOV\u0026#34; def normality_test(time_series, var_name): \u0026#34;\u0026#34;\u0026#34; Perform Normality test based Kolmogorov-Smirnoff (KS) approach. The KS test works well with large data sets. :param time_series: the input time series -\u0026gt; list-like or pandas-like obj :param var_name: name of variable -\u0026gt; str :return: p-value of the normality test --\u0026gt; float \u0026#34;\u0026#34;\u0026#34; if time_series.empty: return None return kstest(time_series, \u0026#34;norm\u0026#34;) significance_level = 0.01 obs = 0 normal= 0 non_normal = 0 # dict below will have shape d = {\u0026#34;AAPL\u0026#34;: No|Yes}, where No indicates non-normal log-returns d = {} for file_path in dataset_dir.iterdir(): stock_ticker = file_path.stem stock_OHLCOV = pd.read_csv(dataset_dir / f\u0026#34;{stock_ticker}.csv\u0026#34;) # log return = ln(P_t / (P_t-1) ) stock_log_return = np.log(stock_OHLCOV[\u0026#34;Close\u0026#34;] / stock_OHLCOV[\u0026#34;Close\u0026#34;].shift(1))[1:] # [1:] to ignore 1st Nan val. test_results = normality_test(stock_log_return, stock_ticker) if test_results is not None: obs += 1 if test_results.pvalue \u0026lt; significance_level: # reject null hypothesis of normality non_normal += 1 d[stock_ticker] = \u0026#34;No\u0026#34; else: normal += 1 d[stock_ticker] = \u0026#34;Yes\u0026#34; # Summary statistics print(\u0026#34;Total observations: \u0026#34;, obs) print(\u0026#34;Normal log-returns: \u0026#34;, normal) print(\u0026#34;Non-normal log-returns: \u0026#34;, non_normal) normal_over_total = round((normal / obs) * 100, 2) print(\u0026#34;Normal/Total: \u0026#34;, normal_over_total, \u0026#34;%\u0026#34;) # Convert dictionary d to pandas Dataframe df = pd.DataFrame(d.items(), columns=[\u0026#34;Symbol\u0026#34;, \u0026#34;Normal log-returns\u0026#34;]) Results of the normality test (massive table ahead!) # Details Symbol Normal log-returns 0 HBNC No 1 CMFN No 2 HFXI No 3 ADMP No 4 MPLX No 5 SAIA No 6 CLGX No 7 CRK No 8 FTS No 9 CTG No 10 SSNC No 11 NUO No 12 CFA No 13 RPD No 14 YLDE No 15 ON No 16 CALL No 17 INGN No 18 BCOR No 19 BBX No 20 PG No 21 GLAD No 22 ATEN No 23 PRIM No 24 ERGF No 25 ESGL No 26 VRSN No 27 VIPS No 28 AGEN No 29 MFO No 30 AMRB No 31 SSW No 32 REVG No 33 BANC_D No 34 CHCI No 35 DPST No 36 PPL No 37 SNDE No 38 WBIF No 39 ENTR Yes 40 GWR No 41 AWP No 42 WLTW No 43 CVR No 44 TOO No 45 LADR No 46 RFDA No 47 JMBA No 48 NVGS No 49 BAC_L No 50 HPQ No 51 HEWY No 52 OC No 53 PRE_H No 54 DLTR No 55 GDDY No 56 BELFA No 57 GTHX No 58 BNFT No 59 ORIT No 60 JNP No 61 ATRS No 62 PRSS No 63 MVF No 64 FRBA No 65 FBM No 66 FL No 67 TFSL No 68 PFBI No 69 FITBI No 70 TCF No 71 REPH No 72 KEMQ No 73 LIVN No 74 ZUMZ No 75 FTXH No 76 GGP No 77 MYOV No 78 ILG No 79 XNTK No 80 EAD No 81 CSII No 82 EQM No 83 AEIS No 84 LTRPB No 85 UNT No 86 GHL No 87 CALD No 88 UN No 89 COLL No 90 AHT_D No 91 KKR_A No 92 BDJ No 93 KEM No 94 ANGO No 95 WAFD No 96 MCK No 97 JACK No 98 CSA No 99 HTH No 100 XLNX No 101 RELV No 102 CBMXW No 103 RADA No 104 SNMX No 105 GIB No 106 OVID No 107 TLEH No 108 LAUR No 109 JOUT No 110 TOO_A No 111 QADA No 112 SCHW_D No 113 OLD No 114 SATS No 115 TYL No 116 FOXA No 117 RMNIU No 118 WFC_N No 119 GFF No 120 HQH No 121 AHPI No 122 MSA No 123 HZNP No 124 OLN No 125 COMG No 126 HGH No 127 ITCB No 128 PRAN No 129 SAN_A No 130 CUTR No 131 VUZI No 132 BIIB No 133 STAR_E No 134 OZRK No 135 CRVL No 136 HTA No 137 MLSS No 138 TICCL No 139 HURN No 140 CIGI No 141 BATRK No 142 NOVN No 143 JYNT No 144 STWD No 145 MLNT No 146 FND No 147 PM No 148 CXE No 149 SPB No 150 CLRO No 151 BUSE No 152 CFR_A No 153 NULG No 154 HRB No 155 DEX No 156 SLDA No 157 UHT No 158 FELP No 159 GDEN No 160 BSQR No 161 ATO No 162 BKJ No 163 IPWR No 164 AXR No 165 WBIG No 166 RIVR No 167 ACH No 168 COST No 169 DHDG No 170 JOF No 171 GFN No 172 TECH No 173 SNCR No 174 HLNE No 175 SFB No 176 LAQ No 177 APD No 178 HVT-A No 179 YIN No 180 PCG_D No 181 TTS No 182 SPI No 183 TMK_B No 184 ADMA No 185 NFEC No 186 NGD No 187 CRH No 188 EOD No 189 AREX No 190 EKSO No 191 FLMB Yes 192 DTE No 193 AU No 194 MS_F No 195 WEYS No 196 SALT No 197 UTMD No 198 LEJU No 199 NFLX No 200 NG No 201 TTAI No 202 SMSI No 203 CZZ No 204 BRCD No 205 SPPP No 206 EGLE No 207 TROX No 208 FFBC No 209 NVR No 210 RGLS No 211 NBD No 212 BRKL No 213 TCCO No 214 HCHC No 215 NUSC No 216 CIO No 217 OFS No 218 NYT No 219 AIMC No 220 NNI No 221 CIZN No 222 KLAC No 223 FIX No 224 TNP_C No 225 TRS No 226 WIFI No 227 TBNK No 228 CMLS No 229 CCA No 230 VRTSP No 231 HYHG No 232 MFUS No 233 KMI No 234 MSCC No 235 CHT No 236 MAV No 237 EEQ No 238 GNT_A Yes 239 MHNC No 240 BBOX No 241 DDR_J No 242 BCACW No 243 SPLP_T No 244 XHR No 245 BCI No 246 HDAW No 247 CXSE No 248 SNV_C No 249 NW_C-CL No 250 XSHD No 251 TLRA No 252 PGC No 253 LPI No 254 FORD No 255 OA No 256 GBNK No 257 MTLS No 258 NSIT No 259 CNFR No 260 CLNS_C-CL No 261 CLNS_B No 262 VRIG No 263 DNI No 264 VALX No 265 BYD No 266 PQ No 267 JSYNU No 268 MIN No 269 ICCC No 270 OZM No 271 AMED No 272 SGU No 273 TELL No 274 BMCH No 275 CINR No 276 DSE No 277 KBLMR No 278 WCC No 279 FFIC No 280 GBAB No 281 CVG No 282 NEA No 283 TNC No 284 PFIN No 285 INGR No 286 GRA No 287 LEG No 288 FPI No 289 BML_I No 290 UIHC No 291 HUM No 292 FTAI No 293 EMO No 294 SMBK No 295 JBK No 296 HBB No 297 CSRA No 298 TIS No 299 CELP No 300 VIVO No 301 DAR No 302 SBH No 303 NTIC No 304 SPE_B No 305 ARDX No 306 DDJP No 307 AVB No 308 QXTR No 309 TCRD No 310 CDXS No 311 TREC No 312 KEY No 313 RMD No 314 WYIGW No 315 ULTI No 316 NTN No 317 CBK No 318 GPACU No 319 IVZ No 320 BFK No 321 REXX No 322 NAT No 323 OASM No 324 SUI_A No 325 GMLP No 326 PRAH No 327 CMSS Yes 328 HTM No 329 RIVRW Yes 330 CJ No 331 JBGS No 332 CCF No 333 BIOS No 334 REEM No 335 UDR No 336 TTEK No 337 CARV No 338 LCNB No 339 STE No 340 AWX No 341 APRN No 342 TANNL No 343 FMCIU No 344 ACFC No 345 JMF No 346 SAFM No 347 JPN No 348 PFI No 349 TZOO No 350 RNSC No 351 EXFO No 352 TEI No 353 EXXI No 354 MTW No 355 NUMG No 356 SNDR No 357 NM_G No 358 DLB No 359 SKX No 360 QMOM No 361 PYS No 362 AGN No 363 BHV No 364 DDLS No 365 QCOM No 366 JOB No 367 NDSN No 368 HSY No 369 SVM No 370 PXLW No 371 GLT No 372 VDTH No 373 SITE No 374 RFP No 375 FUSB No 376 PUK_A No 377 MGPI No 378 HCCI No 379 FNBG No 380 CM No 381 ENOR No 382 CHTR No 383 DLR_I No 384 AUBN No 385 PAYX No 386 GLU No 387 IRM No 388 PZZA No 389 IPOS No 390 MRSN No 391 CBT No 392 NHA No 393 NGHCP No 394 KAR No 395 ACRX No 396 DPW No 397 MTB-WS No 398 XTNT No 399 SBNY No 400 VESH No 401 GLBR No 402 PIRS No 403 PCG_B No 404 RXN No 405 NEE No 406 CWST No 407 GOOGL No 408 FLXS No 409 LCM No 410 PAY No 411 AUPH No 412 RFTA No 413 OBLN No 414 REV No 415 RIC No 416 GCV_B No 417 GTIM No 418 PERY No 419 BNDC No 420 JMPB No 421 BLE No 422 KYO No 423 IDXG No 424 MTG No 425 DPS No 426 OBCI No 427 RCG No 428 HMTV No 429 DKL No 430 IFON No 431 NBW No 432 AFMD No 433 SSRM No 434 JCO No 435 ALL_C No 436 HOVNP No 437 MCBC No 438 CTEK No 439 SOV_C No 440 BDCZ No 441 DVP No 442 FTI No 443 STNG No 444 BW No 445 MDGL No 446 STML No 447 AOI No 448 HAE No 449 TRVG No 450 GAB_G No 451 SBCP No 452 OCLR No 453 HCA No 454 AMH No 455 MKSI No 456 CTBI No 457 FALN No 458 CATYW No 459 GIL No 460 PIXY No 461 CYTR No 462 WAIR No 463 ATSG No 464 UVE No 465 EGLT No 466 SBRAP No 467 ICAN No 468 RNG No 469 CENTA No 470 THM No 471 DS_D No 472 OEUH No 473 BANF No 474 VNLA No 475 NMM No 476 CSTM No 477 GFNSL No 478 ELC No 479 ANDX No 480 LSVX No 481 ZJZZT Yes 482 ABTX No 483 ALRM No 484 HLG No 485 CCZ No 486 MSG No 487 HOPE No 488 DJD No 489 ONSIZ No 490 UNFI No 491 MLPB Yes 492 TWMC No 493 CRIS No 494 HBHCL No 495 RYAM No 496 HGSD No 497 GG No 498 GSL_B No 499 GNRX No 500 FFWM No 501 IDXX No 502 BLRX No 503 ROAM No 504 AHPAU No 505 NSC No 506 GFNCP No 507 FMC No 508 SNMP No 509 BRID No 510 FNJN No 511 SVA No 512 KPTI No 513 CLM No 514 PMBC No 515 YTRA No 516 GJV No 517 FBIZ No 518 BLVDW No 519 KTH No 520 CMPR No 521 PX No 522 FAST No 523 HR No 524 CNDF No 525 BKEP No 526 C_K No 527 AED No 528 FPT No 529 BEBE No 530 APTI No 531 DLX No 532 PSA_E No 533 LVHB No 534 ATLO No 535 ZBK No 536 ELGX No 537 WB No 538 DNR No 539 SSYS No 540 APOP No 541 ALB No 542 NTL No 543 SBSI No 544 MCX No 545 FTR No 546 MTX No 547 IAC No 548 NEE_R No 549 TRP No 550 CNMD No 551 CABO No 552 PSA_G No 553 CXDC No 554 IMNP No 555 PY No 556 ALQA No 557 NEWM No 558 PEI No 559 WFC No 560 IVTY No 561 TEP No 562 XITK No 563 WPPGY No 564 MDP No 565 NYLD No 566 RESN No 567 NSP No 568 RHT No 569 TERM No 570 CIM_B No 571 AA No 572 STX No 573 ACXM No 574 KSU No 575 XLRE No 576 CMCSA No 577 LOAN No 578 NANO No 579 FEYE No 580 GSIE No 581 BIOL No 582 SNAK No 583 SLG No 584 RUTH No 585 BTEC No 586 HALL No 587 ITG No 588 BSWN No 589 NUE No 590 NIM No 591 CRI No 592 VRNA No 593 TCCB No 594 LION No 595 NH No 596 NHI No 597 NTWK No 598 GNMK No 599 FINL No 600 ENB No 601 SWIN No 602 STI-WS-A No 603 CNI No 604 PAC No 605 NTC No 606 MDC No 607 ONDK No 608 JQC No 609 NCTY No 610 HQY No 611 VOXX No 612 QTWO No 613 COO No 614 VBIV No 615 ETR No 616 SAL No 617 PHG No 618 EXTN No 619 CLW No 620 IPHI No 621 FEIM No 622 INCY No 623 KODK No 624 MXDU No 625 YECO No 626 FDEU No 627 HMNF No 628 RLJ No 629 CERCW No 630 YRCW No 631 MSDIW No 632 ESNC No 633 OMEX No 634 SKIS No 635 ENLK No 636 WSO No 637 NVS No 638 HYH No 639 NOC No 640 WM No 641 PNC_P No 642 IBML No 643 PLYM No 644 CNX No 645 PCG_E No 646 LSXMB No 647 ROYT No 648 AMRS No 649 CDZI No 650 TCMD No 651 BOKFL No 652 PENN No 653 GNMX No 654 CFFN No 655 EQRR No 656 ZBH No 657 BUZ No 658 FRME No 659 GLMD No 660 RISE No 661 DMRC No 662 SF_A No 663 CSX No 664 GOF No 665 BCD No 666 WNC No 667 SKYW No 668 MBWM No 669 EXAS No 670 IRR No 671 MCRI No 672 C-WS-A No 673 CRWS No 674 WUSA No 675 ORAN No 676 ACU No 677 TUP No 678 PATI No 679 MSCA No 680 CRM No 681 INVE No 682 IART No 683 AHT_H No 684 ADMS No 685 CBM No 686 BPL No 687 GRAM No 688 TOWN No 689 HCN_I No 690 RLGT No 691 DKT No 692 UNH No 693 HPS No 694 WBII No 695 EMES No 696 OAS No 697 FRC_C No 698 WAYN No 699 CCBG No 700 LORL No 701 MPAC No 702 FTFT No 703 CFRX No 704 HOML No 705 FCN No 706 SOL No 707 HF No 708 LND No 709 FRBK No 710 CNTY No 711 TCBK No 712 FRC_H No 713 LSTR No 714 BGIO No 715 NEO No 716 GER No 717 GZT No 718 CELG No 719 TPR No 720 WEC No 721 RIBT No 722 KO No 723 STFC No 724 PBCT No 725 NBRV No 726 IMPV No 727 ANTM No 728 FBR No 729 IRDMB No 730 MACK No 731 CKH No 732 AWRE No 733 BRG_A No 734 LYG No 735 JASN No 736 EOG No 737 CVM-WS No 738 CALM No 739 TETF No 740 BHE No 741 WSKY No 742 STDY No 743 MTBC No 744 EMCI No 745 DHIL No 746 LOGM No 747 PSB_W No 748 EVO No 749 NEWTZ No 750 GCVRZ No 751 UFPI No 752 OXLCO No 753 IVR No 754 FDS No 755 ARNC_B No 756 APH No 757 CETXP No 758 OSK No 759 CATO No 760 ERF No 761 TLRD No 762 TCHF No 763 ORBK No 764 LSXMK No 765 USVM No 766 HDSN No 767 MHLD No 768 ESGF No 769 NXR No 770 KTEC No 771 SCSC No 772 BRG_C No 773 VSMV No 774 FII No 775 NCA No 776 HLIT No 777 EMN No 778 GLBS No 779 WRB_C No 780 HEES No 781 LOV No 782 CBMX No 783 BGG No 784 INF No 785 ARD No 786 ROKA No 787 SCG No 788 KSU_ No 789 CVRR No 790 HPF No 791 ODP No 792 KIM_I No 793 EXC No 794 NETE No 795 AT No 796 DDT No 797 TNTR No 798 PKG No 799 MANH No 800 ETHO No 801 CLWT No 802 TCBIW Yes 803 GERN No 804 GEC No 805 SRUNU No 806 VMW No 807 MO No 808 PCG_I No 809 LOMA Yes 810 VVUS No 811 QTS No 812 RMGN No 813 WPX No 814 CLNS_D No 815 DWAQ No 816 RILYZ No 817 RPAI_A-CL No 818 RGEN No 819 PLYM_A No 820 V No 821 IAG No 822 SIR No 823 ALE No 824 TTD No 825 BREW No 826 FISV No 827 PCQ No 828 PSB_T No 829 DTUS No 830 RIV No 831 RBS No 832 PFL No 833 SKM No 834 MFCB No 835 CFBK No 836 CATH No 837 RCL No 838 MSGN No 839 CARG No 840 EVN No 841 NUSA No 842 NULV No 843 CNXC No 844 OILD No 845 ADM No 846 SRRA No 847 BIDU No 848 PSF No 849 MIII No 850 NGL_B No 851 LCUT No 852 AJXA No 853 DUSA No 854 LSCC No 855 COP No 856 PYZ No 857 UIS No 858 OREX No 859 CCIH No 860 PHD No 861 ROKU No 862 CDTX No 863 GSHT No 864 OFIX No 865 BOH No 866 MSCI No 867 OPNT No 868 DD No 869 SBBX No 870 BBT No 871 MXIM No 872 EWGS No 873 PRH No 874 SNHNL No 875 STZ-B No 876 HOG No 877 TRPX No 878 GS_C No 879 PFN No 880 WMB No 881 HLI No 882 MDT No 883 AOS No 884 LDP No 885 ISBC No 886 PCG_A No 887 TNH No 888 BOFIL No 889 CIL No 890 DO No 891 PBR No 892 OMAB No 893 AROC No 894 PAVM No 895 BMLP No 896 PW No 897 BHK No 898 MRLN No 899 ENZ No 900 RNVAZ No 901 DCI No 902 UNF No 903 ORBC No 904 APHB No 905 TEVA No 906 GYRO No 907 ACHV No 908 MEN No 909 MMP No 910 ONCS No 911 MTP No 912 INCR No 913 TCO_K No 914 REED No 915 PSL No 916 SPMD No 917 WAFDW No 918 FCCY No 919 ARWR No 920 TERP No 921 GTE No 922 QEP No 923 EXPD No 924 EFF No 925 SPLP No 926 Q No 927 BTA No 928 GSAT No 929 PSMG No 930 GTO No 931 EVGBC No 932 CGIX No 933 DDR_A No 934 CIEN No 935 DX_B No 936 EEP No 937 DCOM No 938 KTCC No 939 TDJ No 940 RGLB No 941 LPX No 942 OTTR No 943 LBRDA No 944 CLB No 945 POOL No 946 GF No 947 AST No 948 ASRV No 949 XCO No 950 COF_F No 951 GEOS No 952 CLLS No 953 RENX No 954 EACQW No 955 SPXX No 956 SYNC No 957 PBMD No 958 TCI No 959 KGC No 960 DRE No 961 CCNE No 962 IPB No 963 CODI_A No 964 HBHC No 965 NI No 966 FRC_F No 967 TNDM No 968 TPH No 969 DYLS No 970 KIN No 971 ABR_C No 972 GGG No 973 UFS No 974 CGI No 975 STRT No 976 USEQ No 977 BKMU No 978 AMH_F No 979 TXMD No 980 BUR No 981 TPZ No 982 SNX No 983 NSL No 984 DSPG No 985 IDN No 986 UEC No 987 LHO No 988 BRC No 989 DFP No 990 HMLP No 991 SNSS No 992 SWCH No 993 DCF Yes 994 AMGP No 995 EMF No 996 SLF No 997 AMCN No 998 GRBK No 999 CBH No 1000 WMK No 1001 FNV No 1002 ROUS No 1003 MLAB No 1004 CRZO No 1005 JHME No 1006 ALTR Yes 1007 CTS No 1008 GARS No 1009 TBBK No 1010 UGI No 1011 SECO No 1012 SANW No 1013 FLAU Yes 1014 UZA No 1015 ECT No 1016 CTLT No 1017 AIMT No 1018 UBNT No 1019 STAY No 1020 HDB No 1021 IPOA-U No 1022 RODM No 1023 HACW No 1024 PRAA No 1025 FNTEU No 1026 SA No 1027 IBA No 1028 EAGLU No 1029 CHKR No 1030 BONT No 1031 MOGLC No 1032 IGT No 1033 ED No 1034 WST No 1035 CRMT No 1036 ATACU No 1037 PSXP No 1038 ERN No 1039 TRCR Yes 1040 BSPM No 1041 WRI No 1042 NAUH No 1043 WCG No 1044 DOOR No 1045 COTV No 1046 SPMV No 1047 KEQU No 1048 ELSE No 1049 PERI No 1050 WRK No 1051 GJH No 1052 WWD No 1053 LMB No 1054 HDS No 1055 PATK No 1056 HTUS No 1057 JPUS No 1058 IAMXW No 1059 CDEV No 1060 GGAL No 1061 BAP No 1062 FH No 1063 FRSX No 1064 ESGD No 1065 TAC No 1066 BOCH No 1067 EVRI No 1068 FFIU No 1069 GSL No 1070 EGL No 1071 ESRT No 1072 DIAL No 1073 CELGZ No 1074 EVV No 1075 BAC No 1076 AXDX No 1077 CHN No 1078 AJRD No 1079 ICCH No 1080 DLR No 1081 SCE_K No 1082 CYBR No 1083 KALU No 1084 EPR No 1085 DGX No 1086 LSXMA No 1087 MAGA No 1088 CGBD No 1089 NSSC No 1090 HFBL No 1091 BPFHW No 1092 GLRE No 1093 SYN No 1094 CP No 1095 AYTU No 1096 QCP No 1097 IMMR No 1098 BEMO No 1099 PUMP No 1100 FTXD No 1101 ECHO No 1102 CBIO No 1103 KBLMU No 1104 AFHBL No 1105 CSL No 1106 MAMS No 1107 CCOI No 1108 CNO No 1109 LXP No 1110 BZUN No 1111 AXL No 1112 DCPH No 1113 MFL No 1114 CERC No 1115 ROLL No 1116 PDEX No 1117 THC No 1118 MAS No 1119 GSB No 1120 SFM No 1121 UCFC No 1122 FAAR No 1123 NLY_E No 1124 LVNTB Yes 1125 JPM_E No 1126 RCII No 1127 ASTE No 1128 ROCK No 1129 DFRG No 1130 FTRI No 1131 VGFO Yes 1132 WTI No 1133 DSL No 1134 GLP No 1135 HDEE No 1136 JASNW No 1137 SHO_E No 1138 UTI No 1139 ELEC No 1140 GENY No 1141 LMRKO No 1142 STLY No 1143 OCC No 1144 DWLV No 1145 AMBR No 1146 MSD No 1147 ARE No 1148 ASUR No 1149 ONP No 1150 NRK No 1151 STAG_C No 1152 WAB No 1153 TUSK No 1154 GGB No 1155 XWEB No 1156 KBH No 1157 PBB No 1158 SQ No 1159 XLRN No 1160 ECL No 1161 ROSE No 1162 DDEZ No 1163 SAIC No 1164 ESE No 1165 NIQ No 1166 UUU No 1167 PPT No 1168 FCB No 1169 SEM No 1170 IEP No 1171 PKOH No 1172 THW No 1173 PEBK No 1174 MTU No 1175 ADSK No 1176 BBSI No 1177 VFC No 1178 GEVO No 1179 GV No 1180 TWOU No 1181 COKE No 1182 SWK No 1183 RAND No 1184 CCXI No 1185 TER No 1186 MINI No 1187 VNO_L No 1188 BLMN No 1189 SNAP No 1190 CDTI No 1191 BBU No 1192 UNAM No 1193 CBL No 1194 GVP No 1195 MTFBW No 1196 IRMD No 1197 OGS No 1198 DDE No 1199 PFBC No 1200 CBA No 1201 MCA No 1202 JMLP No 1203 HSEB No 1204 TRX No 1205 HIG-WS No 1206 NWPX No 1207 RMAX No 1208 CWAY No 1209 SIFY No 1210 AVDL No 1211 CGEN No 1212 ANDAW No 1213 NE No 1214 IBKCO No 1215 LVLT No 1216 KINS No 1217 TTI No 1218 INWK No 1219 PCYO No 1220 RFFC No 1221 ATOS No 1222 JRJR No 1223 DFND No 1224 AEL No 1225 GAB_D No 1226 FPI_B No 1227 NNC No 1228 ERH No 1229 FLQE No 1230 AFSS No 1231 DRD No 1232 TPGE No 1233 PME No 1234 TMK No 1235 NPTN No 1236 WTID No 1237 SNNA No 1238 WBT No 1239 CATS No 1240 HALO No 1241 FTXN No 1242 FCEF No 1243 FIBK No 1244 NSS No 1245 GSEW No 1246 CET No 1247 NRCIA No 1248 SOHOB No 1249 PSET No 1250 DSM No 1251 SPA No 1252 MMD No 1253 PKE No 1254 NVG No 1255 NVUS No 1256 GLYC No 1257 PCMI No 1258 PMC No 1259 CTRL No 1260 CLRBW No 1261 GEF-B No 1262 KFRC No 1263 GYC No 1264 NAO No 1265 NR No 1266 APAM No 1267 ARMK No 1268 SVT No 1269 SSBI No 1270 ETH No 1271 TTNP No 1272 USATP No 1273 SAM No 1274 MSBF No 1275 AXAS No 1276 NKX No 1277 BMI No 1278 BOX No 1279 PLSE No 1280 CHUBA No 1281 PEI_C No 1282 STT_E No 1283 CNSF No 1284 QNST No 1285 KSA No 1286 KKR No 1287 ITUS No 1288 SDRL No 1289 TV No 1290 RPAI No 1291 RSYS No 1292 ENTL No 1293 FWP No 1294 MFV No 1295 BGFV No 1296 CHEKW No 1297 HT_C No 1298 JPM_B No 1299 ZOES No 1300 HIE No 1301 KALA No 1302 TCBIP No 1303 WMIH No 1304 TOT No 1305 IPDN No 1306 KFS No 1307 EML No 1308 TTMI No 1309 FDBC No 1310 PFSI No 1311 DFS No 1312 IOSP No 1313 VSAR No 1314 CRF No 1315 MBIN No 1316 ATNI No 1317 SGC No 1318 ICUI No 1319 GES No 1320 HE No 1321 XTH No 1322 HIX No 1323 NLS No 1324 RFT No 1325 WILC No 1326 OIS No 1327 LANDP No 1328 BLDR No 1329 DEO No 1330 CLYH No 1331 LKFN No 1332 KAMN No 1333 CPSH No 1334 WFBI No 1335 COOL No 1336 SSL No 1337 FNHC No 1338 DFVS No 1339 PCTI No 1340 STM No 1341 SMTS No 1342 SPLB No 1343 CIF No 1344 FMBI No 1345 SBBP No 1346 CPST No 1347 FLIC No 1348 TVC No 1349 DYNC No 1350 UMPQ No 1351 PFFD No 1352 ASC No 1353 MAA No 1354 CETX No 1355 MBRX No 1356 ESGG No 1357 EVA No 1358 STLR No 1359 HDLV No 1360 AUDC No 1361 ORG No 1362 COR_A-CL No 1363 SPH No 1364 SNOA No 1365 PN No 1366 CZR No 1367 LAND No 1368 RILYL No 1369 CR No 1370 MCO No 1371 TDG No 1372 TKF No 1373 ZIXI No 1374 LC No 1375 DEZU No 1376 PSB No 1377 FLEX No 1378 LRN No 1379 KREF No 1380 VR_A No 1381 CLDT No 1382 KRNY No 1383 GIII No 1384 HMG No 1385 ABIL No 1386 WFC_R No 1387 KIM_L No 1388 CHA No 1389 JPSE No 1390 GABR Yes 1391 FSBC No 1392 HSEA No 1393 TA No 1394 VGZ No 1395 IPHS No 1396 RWT No 1397 BKK No 1398 WTFC No 1399 PBFX No 1400 PEIX No 1401 FDEF No 1402 GOODM No 1403 DWDP No 1404 KIM_K No 1405 HRZN No 1406 COWZ No 1407 ERM No 1408 CCS No 1409 NTLA No 1410 WMGI No 1411 ABIO No 1412 MA No 1413 YLD No 1414 PDCO No 1415 UBS No 1416 GSS No 1417 CNHX Yes 1418 ASPN No 1419 LENS No 1420 INTG No 1421 JRVR No 1422 GTYHU No 1423 IRWD No 1424 GGO No 1425 UBSH No 1426 HPI No 1427 PSB_U No 1428 TRST No 1429 NXEO No 1430 VC No 1431 BIF No 1432 BHLB No 1433 VDSI No 1434 IRIX No 1435 MCRB No 1436 CTRN No 1437 DD_B No 1438 MN No 1439 CLI No 1440 SB_C No 1441 ONEY No 1442 FMX No 1443 TWX No 1444 S No 1445 OEC No 1446 RNEM No 1447 BKD No 1448 SELB No 1449 MAR No 1450 LIQT No 1451 VRTU No 1452 LBY No 1453 PETZ No 1454 TSRO No 1455 VSH No 1456 LMFAW No 1457 TWO No 1458 PRGS No 1459 JMP No 1460 SUN No 1461 CNSL No 1462 LNN No 1463 PVAC No 1464 TRTX No 1465 FCRE No 1466 ESS No 1467 BMO No 1468 BETR No 1469 WFC-WS No 1470 ESBK No 1471 KLIC No 1472 WEN No 1473 AETI No 1474 MTN No 1475 NM No 1476 WRE No 1477 CATY No 1478 KEMP No 1479 TSS No 1480 NEWTL No 1481 UPLD No 1482 MERC No 1483 BXP No 1484 CEVA No 1485 GASS No 1486 WBIL No 1487 PSA_Y No 1488 SONS No 1489 EFII No 1490 PSA_Z No 1491 WHLRP No 1492 SKYS No 1493 EV No 1494 BAH No 1495 AQXP No 1496 CCJ No 1497 MPVD No 1498 HZO No 1499 SBFG No 1500 MLNK No 1501 LMHA No 1502 MGA No 1503 ROK No 1504 ALX No 1505 PLW No 1506 MDB No 1507 AMSC No 1508 VVR No 1509 USOI No 1510 LOB No 1511 REFR No 1512 OIA No 1513 TGTX No 1514 RQI No 1515 CNA No 1516 ENTA No 1517 STRS No 1518 SFHY No 1519 HEUV No 1520 PRE_I No 1521 JTA No 1522 PPBI No 1523 AMRK No 1524 VLT No 1525 BPOPM No 1526 ASPU No 1527 TIME No 1528 SBBC No 1529 GTN No 1530 SONA No 1531 TPGE-U No 1532 TCBI No 1533 BMRN No 1534 SPXE No 1535 AVHI No 1536 TACOW No 1537 GSV No 1538 GAZB No 1539 XNY No 1540 DOTAR Yes 1541 GAIN No 1542 TCP No 1543 DXYN No 1544 BCOV No 1545 KLDX No 1546 JPM_F No 1547 NBO No 1548 ISMD No 1549 SEED No 1550 CSTE No 1551 CHRW No 1552 MITT No 1553 AJG No 1554 LGND No 1555 RRR No 1556 LGCY No 1557 NAV_D No 1558 NXJ No 1559 DFS_B No 1560 SCM No 1561 LKOR No 1562 SCON No 1563 SPVM No 1564 IXYS No 1565 ABEOW No 1566 R No 1567 SPLG No 1568 DTYL No 1569 SPLP_A No 1570 CVX No 1571 PMTS No 1572 TMQ No 1573 AIF No 1574 REN No 1575 PRGO No 1576 KSS No 1577 JP No 1578 HCI No 1579 VHC No 1580 EACQ No 1581 TBI No 1582 ELECW No 1583 WBBW No 1584 OTEL No 1585 EXD No 1586 PRTY No 1587 KIORW Yes 1588 NTRSP No 1589 ETV No 1590 SPEM No 1591 LMRKP No 1592 DSX No 1593 TCF_C No 1594 HBM No 1595 USM No 1596 FCBC No 1597 NUS No 1598 HJV No 1599 DBL No 1600 AAWW No 1601 HUSA No 1602 CEM No 1603 NRIM No 1604 POWI No 1605 BCEI No 1606 ATRA No 1607 RMBL No 1608 SUSC No 1609 TANH No 1610 CFMS No 1611 VLRX No 1612 DFFN No 1613 BRQS No 1614 EMJ No 1615 GAM_B No 1616 CCE No 1617 MVT No 1618 GST No 1619 UTG No 1620 PLM No 1621 MSON No 1622 BEAT No 1623 PSB_X No 1624 SRE No 1625 SAND No 1626 ACST No 1627 SCACW No 1628 CCI No 1629 IHG No 1630 WAT No 1631 APB No 1632 MRO No 1633 CSGP No 1634 ALV No 1635 BPOPN No 1636 ERJ No 1637 CPE_A No 1638 EVIX No 1639 SB_B No 1640 OFC No 1641 CTMX No 1642 IMUC-WS No 1643 ARI_C No 1644 WASH No 1645 FMO No 1646 UPL No 1647 PII No 1648 REXR_A No 1649 OSPRW Yes 1650 AZPN No 1651 XBIO No 1652 SIVBO No 1653 PLXS No 1654 SLNOW No 1655 GCAP No 1656 PLUS No 1657 FBNK No 1658 LH No 1659 MPB No 1660 ERIC No 1661 BGC No 1662 HE_U No 1663 URG No 1664 BAM No 1665 APVO No 1666 EPZM No 1667 USAC No 1668 PEB_C No 1669 HOME No 1670 HBANP No 1671 ABB No 1672 PTIE No 1673 BHACW No 1674 GIGM No 1675 TCS No 1676 VSM No 1677 ORA No 1678 CYBE No 1679 MER_K No 1680 WPXP No 1681 MGLN No 1682 ENDP No 1683 ACGL No 1684 VRTV No 1685 NL No 1686 YGE No 1687 NPN No 1688 RDS-A No 1689 STI_E No 1690 IGRO No 1691 ISRL No 1692 NQP No 1693 AMH_G No 1694 HBK No 1695 SNDX No 1696 SCLN No 1697 ATTO No 1698 CWBC No 1699 GNRT No 1700 UBA No 1701 DLTH No 1702 NFG No 1703 WPCS No 1704 FLCH Yes 1705 RPT No 1706 CBOE No 1707 APF No 1708 SUPN No 1709 PPLN No 1710 FLWS No 1711 GT No 1712 KONA No 1713 AKTS No 1714 CNACU No 1715 DSKEW No 1716 WAGE No 1717 TY_ No 1718 ORRF No 1719 BMRC No 1720 CPHI No 1721 BHVN No 1722 FUND No 1723 INBKL No 1724 ALL_F No 1725 AGNCB No 1726 CE No 1727 TIVO No 1728 KRA No 1729 FIVN No 1730 CYD No 1731 AXTI No 1732 LVHD No 1733 AVH No 1734 CUBI_F No 1735 LLNW No 1736 DSS No 1737 GLOG_A No 1738 LUK No 1739 EIGR No 1740 FSTR No 1741 RAIL No 1742 DF No 1743 JDD No 1744 TCBIL No 1745 GPACW No 1746 IF No 1747 CDNA No 1748 ONTX No 1749 QXGG No 1750 OIIL No 1751 ZIOP No 1752 ECR No 1753 DFS_B-CL Yes 1754 AGM_C No 1755 TRMK No 1756 LVHI No 1757 NBY No 1758 TPOR No 1759 SEE No 1760 STKL No 1761 GEMP No 1762 SNSR No 1763 VIA No 1764 QTM No 1765 BEDU No 1766 RYI No 1767 WOR No 1768 AFSI_F No 1769 VFL No 1770 CNQ No 1771 CBZ No 1772 MKC No 1773 BPOP No 1774 CY No 1775 CUB No 1776 CG No 1777 FTF No 1778 UVSP No 1779 NPO No 1780 NEM No 1781 INDUU No 1782 FFBW No 1783 EXPR No 1784 INFR No 1785 EBIX No 1786 POPE No 1787 THGA No 1788 TPIC No 1789 EXPE No 1790 ACOR No 1791 ENT No 1792 SPGI No 1793 JELD No 1794 HAWK No 1795 WFC_W No 1796 AFB No 1797 RT No 1798 SCD No 1799 SWZ No 1800 CBTX Yes 1801 EUDV No 1802 NLY_F No 1803 PEI_B No 1804 PHI No 1805 IBN No 1806 CMSSU No 1807 ADXSW No 1808 NBLX No 1809 ALFI No 1810 FFC No 1811 HEFV No 1812 COF_C No 1813 SBNB No 1814 WRB_B No 1815 CMD No 1816 LCII No 1817 RAS_A No 1818 HNW No 1819 KALV No 1820 P No 1821 CCCR No 1822 TAP No 1823 BCOM No 1824 TGH No 1825 NAVG No 1826 ACRS No 1827 INTU No 1828 NWS No 1829 JBLU No 1830 ONSIW No 1831 DWAC No 1832 ENV No 1833 HIPS No 1834 TDE No 1835 BAC_I No 1836 SEIC No 1837 BOOT No 1838 WBS No 1839 CRNT No 1840 SCWX No 1841 LNDC No 1842 IGZ Yes 1843 RTTR No 1844 BRS No 1845 ANY No 1846 VNO_I No 1847 LPL No 1848 IVR_B No 1849 CRMD No 1850 PWR No 1851 DWCH No 1852 SNBC No 1853 WTFCW No 1854 PJH No 1855 BBC No 1856 SXI No 1857 GWPH No 1858 INFU No 1859 SLB No 1860 DWAT No 1861 SHOO No 1862 SSD No 1863 DEA No 1864 CX No 1865 AKO-A No 1866 CLIRW No 1867 BGX No 1868 EVTC No 1869 MIC No 1870 CHH No 1871 BNY No 1872 AMKR No 1873 ECC No 1874 WBIH No 1875 ECCB No 1876 ASML No 1877 NXC No 1878 FTD No 1879 STI-WS-B No 1880 ABR_A No 1881 DIT No 1882 PSA_F No 1883 MAGS No 1884 NAIL No 1885 TTP No 1886 CPL No 1887 AMP No 1888 UMH_B No 1889 GPT No 1890 EDAP No 1891 IBDS No 1892 KEX No 1893 WLDN No 1894 HUBG No 1895 NHLD No 1896 QLC No 1897 ABRN No 1898 ASET No 1899 SGLB No 1900 WBIB No 1901 BELFB No 1902 ES No 1903 CSBK No 1904 RIF No 1905 PYDS No 1906 CJJD No 1907 SD No 1908 TCON No 1909 LBTYK No 1910 FEN No 1911 TI No 1912 YEXT No 1913 ANET No 1914 SBRA No 1915 WF No 1916 GDV_G No 1917 GLADN No 1918 KRG No 1919 BIO-B No 1920 IFIX No 1921 NYCB_U No 1922 TCO_J No 1923 PTX No 1924 TIG No 1925 CHD No 1926 GKOS No 1927 FRD No 1928 LGCYP No 1929 AGO_F No 1930 WSM No 1931 BBT_F No 1932 OXY No 1933 WSTL No 1934 TWI No 1935 WBIA No 1936 FBHS No 1937 GLOP No 1938 ESGW No 1939 LECO No 1940 JMM No 1941 DHY No 1942 WABC No 1943 IMMY No 1944 IPXL No 1945 JVA No 1946 TKAT No 1947 ARDM No 1948 KONE No 1949 VMIN No 1950 DIVY No 1951 BEF Yes 1952 PSTG No 1953 MMDM No 1954 EVM No 1955 FLQS No 1956 HY No 1957 MFM No 1958 NDRAW No 1959 EMGF No 1960 EQR No 1961 CUBI No 1962 VRTX No 1963 PSDV No 1964 NK No 1965 WIRE No 1966 BLK No 1967 IIF No 1968 PWOD No 1969 BOSS No 1970 GRPN No 1971 VNTR No 1972 MAT No 1973 ZX No 1974 MYNDW No 1975 GWB No 1976 PBUS No 1977 GMLPP Yes 1978 FTEK No 1979 CAC No 1980 CPHC No 1981 COF-WS No 1982 EPM No 1983 BWINB No 1984 TRC No 1985 HEWP No 1986 KT No 1987 GHYB No 1988 SRLP No 1989 OPGNW No 1990 PDS No 1991 OTTW No 1992 PDLI No 1993 GTS No 1994 PNNT No 1995 TEL No 1996 NRT No 1997 MEOH No 1998 SPMO No 1999 STAG_B No 2000 GRX_B No 2001 UBP_F-CL No 2002 BCS No 2003 BLVD No 2004 SPTL No 2005 MUSA No 2006 APRI No 2007 BIBL Yes 2008 JRJC No 2009 GBLI No 2010 AZO No 2011 SORL No 2012 MLPQ No 2013 JHI No 2014 DALT No 2015 GE No 2016 ATR No 2017 FNCF No 2018 XIVH No 2019 WOW No 2020 WBIR No 2021 FTVA Yes 2022 AABA No 2023 FLQL No 2024 AVXL No 2025 DLR_J No 2026 TPX No 2027 KBWB No 2028 HSNI No 2029 GOOD No 2030 YUMC No 2031 AI No 2032 ASV No 2033 PSMC No 2034 FUN No 2035 NC No 2036 IPCI No 2037 FLY No 2038 AMS No 2039 CMRE_B No 2040 DD_A No 2041 VTNR No 2042 MFC No 2043 VREX No 2044 MTOR No 2045 TNP_E No 2046 FRAN No 2047 LLEX No 2048 VMM No 2049 NAC No 2050 HSKA No 2051 WMLP No 2052 FNF No 2053 NEV No 2054 LHO_J No 2055 PTEN No 2056 MBTF No 2057 ARNC_ No 2058 CEMB No 2059 CHEF No 2060 ESDI No 2061 JPXN No 2062 GGZR Yes 2063 CLTL No 2064 MUJ No 2065 NWE No 2066 CEZ No 2067 DEPO No 2068 KANG No 2069 LVUS No 2070 VOD No 2071 TISA No 2072 SPPI No 2073 THFF No 2074 USLM No 2075 SIEN No 2076 TECK No 2077 GST_A No 2078 MLPZ No 2079 EYES No 2080 DGLT No 2081 STO No 2082 GTY No 2083 HEI No 2084 ALSK No 2085 HCLP No 2086 WAL No 2087 MFIN No 2088 PCAR No 2089 BX No 2090 PRPH No 2091 NEE_Q No 2092 ALKS No 2093 SWN No 2094 SPYX No 2095 SOGO Yes 2096 YOGA No 2097 SDVY Yes 2098 AXU No 2099 MGIC No 2100 KAI No 2101 VGR No 2102 OBSV No 2103 TRMT No 2104 FOSL No 2105 DLBR No 2106 BLVDU No 2107 NGVC No 2108 ORC No 2109 SPXN No 2110 NXTDW No 2111 CNS No 2112 HBIO No 2113 VER_F No 2114 LTS No 2115 PBI No 2116 RMNI No 2117 ASGN No 2118 SNHY No 2119 TGNA No 2120 MICR No 2121 LBAI No 2122 GRMY Yes 2123 PFGC No 2124 CEMI No 2125 SHO_F No 2126 BIG No 2127 WEX No 2128 RLOG No 2129 KRNT No 2130 RNR No 2131 CXH No 2132 GHDX No 2133 AFSD No 2134 BEP No 2135 BTO No 2136 TESO No 2137 PRI No 2138 BVXV No 2139 MCEP No 2140 BBT_D No 2141 UHS No 2142 HWKN No 2143 SECT No 2144 DEEF No 2145 GWGH No 2146 UBCP No 2147 ROL No 2148 CHFS No 2149 CEQP No 2150 IPCC No 2151 APTO No 2152 EMR No 2153 FN No 2154 RDHL No 2155 KRP No 2156 DX_A No 2157 RFUN No 2158 SPSC No 2159 SYBX No 2160 NYV No 2161 VRX No 2162 ENZY No 2163 PRA No 2164 TDC No 2165 AEM No 2166 EIP No 2167 KMT No 2168 SHLD No 2169 JSYN No 2170 ZVV Yes 2171 CYS_B No 2172 WFT No 2173 TMK_C No 2174 IAE No 2175 HL No 2176 FLL No 2177 ARLZ No 2178 SPNE No 2179 RDUS No 2180 IMOM No 2181 ETFC No 2182 CRVP No 2183 DWFI No 2184 CCLP No 2185 GRNB No 2186 SRTSW No 2187 OACQW No 2188 SYBT No 2189 XOMA No 2190 DHG No 2191 JHML No 2192 RAS_B No 2193 PTF No 2194 KNOP No 2195 DY No 2196 BAC_C No 2197 BAC-WS-A No 2198 MMDMW No 2199 SAVE No 2200 DLR_H No 2201 OLBK No 2202 IDSA No 2203 TURN No 2204 RSO_B No 2205 ARNC No 2206 DLBS No 2207 RXN_A No 2208 TPGE-WS No 2209 PFLT No 2210 PGZ No 2211 INBK No 2212 SCE_D No 2213 LNG No 2214 RGA No 2215 TCAP No 2216 CASM No 2217 PCM No 2218 BPMP No 2219 EZPW No 2220 TIK No 2221 TAT No 2222 CHI No 2223 SBNYW No 2224 PXD No 2225 CSOD No 2226 SRDX No 2227 ATAC No 2228 CMRE No 2229 CVO No 2230 CGNT No 2231 BFY No 2232 KL No 2233 FWRD No 2234 TEUM No 2235 VERU No 2236 NTNX No 2237 ALLY_A No 2238 CSSE No 2239 WLH No 2240 BWLD No 2241 STN No 2242 JCE No 2243 LNTH No 2244 ISR No 2245 CZFC No 2246 FLT No 2247 NEPT No 2248 CRD-A No 2249 WYIG No 2250 HBP No 2251 LNT No 2252 CARS No 2253 CNOB No 2254 MNGA No 2255 STZ No 2256 VTC Yes 2257 KTWO No 2258 CLNT No 2259 INT No 2260 INAP No 2261 VET No 2262 PYPL No 2263 MTB_ No 2264 SPIB No 2265 WSBC No 2266 WAC No 2267 AIRT No 2268 AAN No 2269 LMNX No 2270 JHS No 2271 HTGM No 2272 ITT No 2273 KYE No 2274 AIEQ No 2275 MOSY No 2276 RDS-B No 2277 CPB No 2278 FCE-A No 2279 QUIK No 2280 CRSP No 2281 PSA No 2282 NEN No 2283 CACG No 2284 DRI No 2285 ENO No 2286 FDUS No 2287 SRV No 2288 MG No 2289 IBP No 2290 APEN No 2291 EQS No 2292 NNDM No 2293 GOP No 2294 AIY No 2295 FPP No 2296 CEE No 2297 CRTN No 2298 PAVMW No 2299 IHT No 2300 STT_G No 2301 GOAU No 2302 SILC No 2303 WATT No 2304 BCACR No 2305 BML_G No 2306 EAGL No 2307 BXE No 2308 AVP No 2309 SFNC No 2310 FFHG No 2311 SFUN No 2312 MDLZ No 2313 GPK No 2314 GDL_B No 2315 CAG No 2316 HEMV No 2317 PQG No 2318 EFR No 2319 SLRA No 2320 ZAYO No 2321 PFH No 2322 EVY No 2323 HELE No 2324 CFR No 2325 MIIIU No 2326 NNBR No 2327 BGB No 2328 OI No 2329 KIO No 2330 SPVU No 2331 HUBB No 2332 BGCA No 2333 CSWC No 2334 JNJ No 2335 CVLY No 2336 DDWM No 2337 GS_I No 2338 WEB No 2339 COHN No 2340 RSO No 2341 TMHC No 2342 CUZ No 2343 MCY No 2344 CORI No 2345 RTNB No 2346 LDR No 2347 GAM No 2348 NKSH No 2349 WLKP No 2350 CPK No 2351 AMDA No 2352 JHMI No 2353 XOG No 2354 STT No 2355 GWRS No 2356 GBIL No 2357 EGOV No 2358 DRQ No 2359 RNLC No 2360 HQL No 2361 HES No 2362 ISF No 2363 LOCO No 2364 BRSS No 2365 NGHCN No 2366 NUV No 2367 FXEP No 2368 EGY No 2369 EWRE No 2370 AHT_G No 2371 BWA No 2372 RATE No 2373 IVENC No 2374 CADE No 2375 PLBC No 2376 IGC No 2377 PVBC No 2378 GHC No 2379 OFLX No 2380 GIM No 2381 QVCB No 2382 CUNB No 2383 VRSK No 2384 SHI No 2385 BH No 2386 AER No 2387 ATNX No 2388 MNK No 2389 WHLR No 2390 ESP No 2391 YPF No 2392 ATAI No 2393 FPP-WS No 2394 NYMTP No 2395 TPL No 2396 WFC_T No 2397 GEL No 2398 HYDD No 2399 IDEV No 2400 REFA No 2401 CTR No 2402 HCP No 2403 FDC No 2404 EGBN No 2405 REG No 2406 RIO No 2407 TTOO No 2408 OIIM No 2409 ERA No 2410 KE No 2411 CYTX No 2412 EGN No 2413 VRTS No 2414 PEGA No 2415 KAAC No 2416 LILAK No 2417 VTA No 2418 SDT No 2419 MUE No 2420 RRC No 2421 HUNTU No 2422 SCE_H No 2423 NYNY No 2424 RRTS No 2425 IGR No 2426 NNA No 2427 HII No 2428 BCR No 2429 AMWD No 2430 AGR No 2431 TOL No 2432 AGM No 2433 BBG No 2434 IIN No 2435 SYK No 2436 ADX No 2437 SGBX No 2438 CBFV No 2439 MNRO No 2440 EYESW No 2441 SPRO Yes 2442 STI_A No 2443 NCB No 2444 SNC No 2445 DHX No 2446 HPT No 2447 MPA No 2448 PW_A No 2449 WDRW No 2450 ONTL No 2451 PRU No 2452 OIBR-C No 2453 MBIO No 2454 SWKS No 2455 LANC No 2456 IAMXR No 2457 EGF No 2458 DXLG No 2459 BUD No 2460 AEE No 2461 SYRS No 2462 STPP No 2463 CUBI_C No 2464 MFEM No 2465 GORO No 2466 ABC No 2467 JHMA No 2468 CPLP No 2469 C_J No 2470 DWTR No 2471 BCTF No 2472 KS No 2473 RMBS No 2474 NANR No 2475 SLCA No 2476 HUNTW No 2477 TRT No 2478 SMPL No 2479 RIBTW No 2480 GNT No 2481 ACN No 2482 ETB No 2483 ODFL No 2484 MDGS No 2485 CAJ No 2486 SCI No 2487 MORN No 2488 WCN No 2489 WDR No 2490 FDMO No 2491 PEO No 2492 FCAP No 2493 AQUA Yes 2494 SPWR No 2495 GVA No 2496 CRAI No 2497 DUK No 2498 FRPH No 2499 MCFT No 2500 NYMTO No 2501 RPAI_A No 2502 AGD No 2503 DFVL No 2504 NWY No 2505 LTBR No 2506 IMO No 2507 BPFHP No 2508 XXII No 2509 BHBK No 2510 KRC No 2511 SSN No 2512 CTXR No 2513 NDP No 2514 CQP No 2515 JCP No 2516 AFST No 2517 VEAC No 2518 MTSL No 2519 VNO No 2520 KTF No 2521 VNDA No 2522 JPIH No 2523 AFSI_C No 2524 CDK No 2525 PER No 2526 DVEM No 2527 HFRO Yes 2528 SIEB No 2529 RPT_D No 2530 ITRN No 2531 NYCB_A No 2532 HASI No 2533 GOLD No 2534 AMC No 2535 ELVT No 2536 AVGO No 2537 NZF No 2538 AGU No 2539 AVGR No 2540 OCSL No 2541 ROIC No 2542 PGR No 2543 SOJA No 2544 EDOW No 2545 MGP No 2546 WDAY No 2547 PLG No 2548 YGYI No 2549 BLW No 2550 AVT No 2551 FNGN No 2552 PDFS No 2553 ZDGE No 2554 PBT No 2555 WCFB No 2556 RNDV No 2557 SPKE No 2558 BGS No 2559 SUSA No 2560 GTYH No 2561 MEXX No 2562 VALE-P No 2563 RYAM_A No 2564 BAR No 2565 MX No 2566 SNBR No 2567 FNB_E No 2568 DK No 2569 EFT No 2570 TSLF No 2571 GARD No 2572 LODE No 2573 VCRA No 2574 PESI No 2575 BLX No 2576 PTH No 2577 ZIONW No 2578 MNTA No 2579 KND No 2580 DB No 2581 XENE No 2582 CTV No 2583 HMST No 2584 DLNG No 2585 TRU No 2586 DFIN No 2587 PETQ No 2588 IBDR No 2589 DENN No 2590 IIPR_A No 2591 ZEN No 2592 PID No 2593 SQNS No 2594 CVGI No 2595 LABL No 2596 EDOM No 2597 CMRE_D No 2598 QLYS No 2599 CLNS_I No 2600 LILA No 2601 GNC No 2602 CPN No 2603 AMMA No 2604 FENC No 2605 UONE No 2606 CNET No 2607 DLPH No 2608 CRY No 2609 NXQ No 2610 RBCAA No 2611 ENS No 2612 PBSK No 2613 BDC_B No 2614 WRLSU No 2615 IMRN No 2616 ERIE No 2617 KW No 2618 ATUS No 2619 MLHR No 2620 BA No 2621 QXRR No 2622 LNCE No 2623 CDXC No 2624 AEO No 2625 USB No 2626 PTEU No 2627 BBL No 2628 NAKD No 2629 JHA No 2630 BKEPP No 2631 SIF No 2632 MFSF No 2633 HBCP No 2634 KCNY No 2635 UHAL No 2636 JPM_A No 2637 NBN No 2638 CUBA No 2639 OMAM No 2640 ISG No 2641 BCO No 2642 LMNR No 2643 WSFS No 2644 ALJJ No 2645 BDL No 2646 IFRX Yes 2647 IIM No 2648 FAF No 2649 ABMD No 2650 BVAL No 2651 RVSB No 2652 EPRF No 2653 G No 2654 NJV No 2655 JPME No 2656 CNHI No 2657 MBOT No 2658 UAN No 2659 BVX No 2660 CAR No 2661 ICON No 2662 IMGN No 2663 SRF No 2664 CI No 2665 DLA No 2666 MC No 2667 HTD No 2668 DHI No 2669 TRUP No 2670 MFNC No 2671 PVG No 2672 III No 2673 NUMV No 2674 BLUE No 2675 ALPN No 2676 BAA No 2677 PTNQ No 2678 BCV No 2679 CHFC No 2680 DMTX No 2681 LCAHW No 2682 BLJ No 2683 HEB No 2684 ECA No 2685 TMUS No 2686 CSV No 2687 ALDX No 2688 LW No 2689 TDS No 2690 DIVO No 2691 DSU No 2692 MEAR No 2693 NGVT No 2694 WINS No 2695 EVJ No 2696 GAIA No 2697 WLFC No 2698 TMO No 2699 HMTA No 2700 VVPR No 2701 CAKE No 2702 AOXG No 2703 SHLX No 2704 ERC No 2705 PLAY No 2706 FGEN No 2707 DYN No 2708 ASFI No 2709 VSEC No 2710 NMT No 2711 DIOD No 2712 PRMW No 2713 JCTCF No 2714 ABY No 2715 ARRY No 2716 GLQ No 2717 IFLY No 2718 AES No 2719 FRC No 2720 MGCD No 2721 AAU No 2722 CNCR No 2723 RNDB No 2724 JKS No 2725 UE No 2726 STBZ No 2727 EPR_C No 2728 GGN No 2729 NSTG No 2730 GS_B No 2731 GURE No 2732 RFI No 2733 BCS_D No 2734 ICVT No 2735 ISNS No 2736 BCC No 2737 PFG No 2738 KGJI No 2739 BNCL No 2740 BKT No 2741 JFR No 2742 GLPI No 2743 GNK No 2744 LGIH No 2745 AHPAW No 2746 VVV No 2747 NUVA No 2748 WTS No 2749 GJR No 2750 FCO No 2751 JPM_G No 2752 MCD No 2753 ARKW No 2754 WFC_O No 2755 SWIR No 2756 RBUS No 2757 CVS No 2758 ESTE No 2759 ARKQ No 2760 RNET No 2761 EGP No 2762 PRFT No 2763 HCN No 2764 PNW No 2765 CORR No 2766 GAMR No 2767 DRNA No 2768 CECE No 2769 TGB No 2770 GUDB Yes 2771 PRQR No 2772 WTFCM No 2773 AHT No 2774 SCACU No 2775 CTHR No 2776 IPOA No 2777 ACIW No 2778 PBEE No 2779 PTY No 2780 FSNN No 2781 AVX No 2782 AZRE No 2783 PCN No 2784 MIME No 2785 UFAB No 2786 AMTX No 2787 OCX No 2788 SZC No 2789 ETG No 2790 OACQR No 2791 NCI No 2792 DNB No 2793 ELON No 2794 JPT No 2795 TGLS No 2796 MAN No 2797 MCHP No 2798 XENT No 2799 SPYD No 2800 AVEO No 2801 CMTA No 2802 BAF No 2803 ITI No 2804 GS_N No 2805 EMTL No 2806 KCAP No 2807 CEA No 2808 PVAL Yes 2809 TWO_A No 2810 PLPC No 2811 CKPT No 2812 AVK No 2813 CMCM No 2814 FBP No 2815 VPG No 2816 AKBA No 2817 APPF No 2818 CTIC No 2819 CCO No 2820 KIM No 2821 AHC No 2822 HT_E No 2823 LOPE No 2824 OPK No 2825 HUNT No 2826 GBR No 2827 GTT No 2828 MLM No 2829 MTRN No 2830 LAZ No 2831 ALNY No 2832 CLRB No 2833 ASX No 2834 HPP No 2835 AIT No 2836 IBM No 2837 E No 2838 MH_C No 2839 DDS No 2840 VTVT No 2841 CODX No 2842 SPIL No 2843 PMT_A No 2844 HDMV No 2845 HTBX No 2846 AKP No 2847 SMFG No 2848 MULE No 2849 KBLM No 2850 AIV No 2851 GOL No 2852 CMRE_C No 2853 AXGN No 2854 IBKC No 2855 RIG No 2856 KODK-WS-A No 2857 GNTY No 2858 RFEU No 2859 SUP No 2860 FSI No 2861 ORN No 2862 DTK No 2863 SAB No 2864 SSI No 2865 GPMTW Yes 2866 DIN No 2867 ECYT No 2868 QRVO No 2869 BSM No 2870 CIFS No 2871 LFEQ No 2872 CRCM No 2873 CYS No 2874 ACTG No 2875 BBT_E No 2876 HTRB No 2877 FANG No 2878 INOV No 2879 PRNT No 2880 GRX No 2881 JCOM No 2882 EHT No 2883 DRYS No 2884 CME No 2885 IBMJ No 2886 ABE No 2887 ILMN No 2888 RXDX No 2889 PHT No 2890 MGI No 2891 TGA No 2892 MPV No 2893 AKS No 2894 HSII No 2895 BSCQ No 2896 FLJP Yes 2897 RAVN No 2898 GEN No 2899 SOHOO No 2900 DKS No 2901 EIGI No 2902 YTEN No 2903 WDFC No 2904 PNK No 2905 WGP No 2906 TGS No 2907 BATRA No 2908 IONS No 2909 FLKR Yes 2910 CORT No 2911 CMC No 2912 MYO No 2913 RMNIW No 2914 ANDA No 2915 CCV No 2916 IDCC No 2917 IHC No 2918 ALCO No 2919 ATRI No 2920 FI No 2921 ARES No 2922 SF No 2923 CEN No 2924 TAIT No 2925 KOSS No 2926 BMRA No 2927 EPAM No 2928 EVBG No 2929 NVIV No 2930 PZRX No 2931 IBKR No 2932 TGC No 2933 DTY No 2934 RM No 2935 GAB_J No 2936 PFO No 2937 IDRA No 2938 ABM No 2939 JBN No 2940 MIIIW No 2941 REXR No 2942 IIVI No 2943 MICTW No 2944 HONE No 2945 LOXO No 2946 EMQQ No 2947 LGL No 2948 LBRDK No 2949 CNP No 2950 TCO No 2951 JTD No 2952 AQN No 2953 AMBA No 2954 MVC No 2955 MFDX No 2956 PTNR No 2957 ADTN No 2958 IAM No 2959 CMRX No 2960 IVH No 2961 JHD No 2962 XON No 2963 ATEC No 2964 RNVA No 2965 DGICA No 2966 SYNL No 2967 CERS No 2968 FMAO No 2969 NML No 2970 OVLY No 2971 Y No 2972 OMI No 2973 CLNS No 2974 CARA No 2975 SYF No 2976 COBZ No 2977 GECCL No 2978 MFA_B No 2979 HUN No 2980 CPTAL No 2981 MDVXW No 2982 LRGE No 2983 DSX_B No 2984 WG No 2985 BFR No 2986 SNV No 2987 IRL No 2988 PUK No 2989 NXE No 2990 TGP No 2991 KORS No 2992 GM-WS-B No 2993 IOVA No 2994 OUSA No 2995 CO No 2996 TLGT No 2997 ENSV No 2998 STLD No 2999 HYXE No 3000 MYI No 3001 JAG No 3002 SEB No 3003 WBIE No 3004 AGO_B No 3005 DOV No 3006 FPRX No 3007 USMF No 3008 ATH No 3009 SYX No 3010 WHLRW No 3011 MYJ No 3012 HFC No 3013 EWUS No 3014 IPL_D No 3015 OSIS No 3016 OEUR No 3017 MELR No 3018 ZTS No 3019 OSBC No 3020 CTWS No 3021 RMP No 3022 NVMI No 3023 MRC No 3024 COG No 3025 HEWL No 3026 MMAC No 3027 GRMN No 3028 ITEQ No 3029 SYT No 3030 CHUBK No 3031 KAACW No 3032 AEB No 3033 BHB No 3034 TWNKW No 3035 MYSZ No 3036 DBES No 3037 SHOP No 3038 KOOL No 3039 PPR No 3040 TIPT No 3041 SLNO No 3042 ARGS No 3043 OSLE No 3044 ADSW No 3045 BBRG No 3046 AGYS No 3047 DSXN No 3048 CHW No 3049 GGZ_A No 3050 CNXR No 3051 NDLS No 3052 AAC No 3053 MCI No 3054 MFG No 3055 DAVE No 3056 TPRE No 3057 EIA No 3058 FCF No 3059 RJF No 3060 RHP No 3061 VCEL No 3062 INO No 3063 SIRI No 3064 EVC No 3065 ASB_C No 3066 SJI No 3067 PRLB No 3068 SJW No 3069 GSJY No 3070 EMD No 3071 SEDG No 3072 MBUU No 3073 VIAV No 3074 SLG_I No 3075 ANTX No 3076 AHPA No 3077 MRRL No 3078 MTRX No 3079 RHE No 3080 SNE No 3081 GOLF No 3082 MARA No 3083 NWHM No 3084 SRC_A No 3085 SBR No 3086 PLD No 3087 BWFG No 3088 POST No 3089 AEK No 3090 RGS No 3091 IRET No 3092 MGEE No 3093 YUM No 3094 WY No 3095 NHLDW No 3096 BOMN No 3097 RIGL No 3098 CTSO No 3099 GPRE No 3100 SFR No 3101 ETN No 3102 GNBC No 3103 PRSC No 3104 ALNA Yes 3105 MUS No 3106 NXP No 3107 ICD No 3108 AFSI_E No 3109 NEE_K No 3110 EAT No 3111 SSW_D No 3112 PNC-WS No 3113 XCEM No 3114 BOSC No 3115 MLCO No 3116 PEG No 3117 SHOS No 3118 MSM No 3119 KCAPL No 3120 ARR_A No 3121 PGEM No 3122 SSTK No 3123 AMG No 3124 ANFI No 3125 FGBI No 3126 CHS No 3127 KTN No 3128 NLY No 3129 BKE No 3130 FDVV No 3131 F No 3132 RFDI No 3133 MTH No 3134 BCV_A No 3135 DJCO No 3136 SKY No 3137 CRL No 3138 XPL No 3139 SQLV No 3140 HQCL No 3141 MP_D No 3142 AXS No 3143 KLDW No 3144 MMT No 3145 JE No 3146 EGHT No 3147 HIBB No 3148 DXC No 3149 HON No 3150 FBSS No 3151 PSTB No 3152 FE No 3153 SUNS No 3154 CZWI No 3155 OR No 3156 INTT No 3157 UTHR No 3158 HGT No 3159 CCRC No 3160 KWN-CL No 3161 ACV No 3162 ATVI No 3163 CUBN No 3164 NERV No 3165 DTV No 3166 JHB No 3167 OMN No 3168 WRLS No 3169 ESGE No 3170 PAVE No 3171 EFL No 3172 CLAR No 3173 FRC_E No 3174 MUR No 3175 FRO No 3176 CPSI No 3177 MDLY No 3178 BWEN No 3179 OSG No 3180 ETJ No 3181 BSJP No 3182 COF_H No 3183 FLGT No 3184 FORTY No 3185 EMCF No 3186 MTBCP No 3187 NCNA No 3188 TDI No 3189 FOE No 3190 NVDA No 3191 DPZ No 3192 NEE_C-CL No 3193 PHH No 3194 FDX No 3195 EMSD No 3196 CIVB No 3197 MXF No 3198 CDR_C No 3199 HAFC No 3200 MITL No 3201 BV No 3202 NCLH No 3203 MCC No 3204 FLKS No 3205 PZC No 3206 JCI No 3207 JAZZ No 3208 EVF No 3209 RXIIW No 3210 TVTY No 3211 WSBF No 3212 BASI No 3213 DAC No 3214 TRHC No 3215 FF No 3216 SGY No 3217 NNN_F No 3218 TROW No 3219 CIA No 3220 NPK No 3221 IEC No 3222 NEE_I No 3223 MDU No 3224 MTEM No 3225 HSGX No 3226 EPAY No 3227 OCRX No 3228 SANM No 3229 ISM No 3230 HRG No 3231 BGCP No 3232 RIOT No 3233 CIT No 3234 SGRY No 3235 DLHC No 3236 BLPH No 3237 SGMO No 3238 NGLS_A No 3239 CSTR No 3240 COHR No 3241 ATOM No 3242 CBAY No 3243 KNSL No 3244 FMNB No 3245 TRVN No 3246 CUBS No 3247 TTAC No 3248 ICAD No 3249 WRN No 3250 IVAL No 3251 TYME No 3252 ZYNE No 3253 BSAC No 3254 PINC No 3255 TWLO No 3256 BEL No 3257 ATI No 3258 BLKB No 3259 SPG_J No 3260 AMAG No 3261 VMI No 3262 SIGI No 3263 CZNC No 3264 HRL No 3265 HSBC_A No 3266 IR No 3267 HIW No 3268 BCPC No 3269 HTBI No 3270 SFL No 3271 BK No 3272 LWAY No 3273 BFIT No 3274 LOVW Yes 3275 ETP No 3276 CHK_D No 3277 IRS No 3278 OASI No 3279 PREF No 3280 MMDMU No 3281 BVXVW No 3282 CINF No 3283 DWIN No 3284 APO_A No 3285 NLY_D No 3286 MGM No 3287 DOTAW Yes 3288 CLNS_J No 3289 LBTYA No 3290 STAA No 3291 CTO No 3292 XTLB No 3293 KEP No 3294 USRT No 3295 BB No 3296 BRACU No 3297 GNRC No 3298 SAN_I No 3299 UTF No 3300 SCE_E No 3301 DLBL Yes 3302 MHLA No 3303 RWC No 3304 PVH No 3305 SCMP No 3306 INSG No 3307 ENH_C No 3308 FANZ No 3309 TWTR No 3310 OKTA No 3311 EDGE No 3312 VEC No 3313 ARCM No 3314 COUP No 3315 TESS No 3316 JEC No 3317 BRT No 3318 LARE No 3319 CNTF No 3320 ORMP No 3321 DCP No 3322 IIJI No 3323 TEDU No 3324 ASMB No 3325 JMEI No 3326 IBD No 3327 TRXC No 3328 SSNI No 3329 MNDO No 3330 GNTX No 3331 HSC No 3332 DXCM No 3333 JPEM No 3334 DS_B No 3335 FFKT No 3336 GHYG No 3337 OEW No 3338 LONE No 3339 ALLE No 3340 ADAP No 3341 BDN No 3342 IP No 3343 NCMI No 3344 VCYT No 3345 EPC No 3346 NMR No 3347 PZE No 3348 KMM No 3349 RBA No 3350 GDO No 3351 BANR No 3352 CSS No 3353 INFN No 3354 VSLR No 3355 GIMO No 3356 CRME No 3357 ITIC No 3358 GLUU No 3359 NBHC No 3360 ACCO No 3361 GMZ No 3362 IMUC No 3363 DISCA No 3364 OSBCP No 3365 FCSC No 3366 CATM No 3367 HVT No 3368 JPM_H No 3369 CBSH No 3370 AEG No 3371 FLBR Yes 3372 KR No 3373 CUMB No 3374 CYH No 3375 HBI No 3376 UBP_G No 3377 SCHW_B No 3378 HIIQ No 3379 DOTA No 3380 HEWI No 3381 AGGP No 3382 ETY No 3383 POWL No 3384 MVCB No 3385 UTSL No 3386 RVNC No 3387 CLD No 3388 SENEA No 3389 HCAC-U No 3390 SCHK No 3391 KELYA No 3392 ICB No 3393 VGI No 3394 ORLY No 3395 CAT No 3396 TMST No 3397 FAX No 3398 TANNZ No 3399 KWEB No 3400 FNKO Yes 3401 HGV No 3402 HNRG No 3403 XNET No 3404 BMY No 3405 AMFW No 3406 GUT_C No 3407 MH_D No 3408 MSEX No 3409 CNXN No 3410 CVBF No 3411 OILX No 3412 TEGP No 3413 FPH No 3414 UGP No 3415 FLIO No 3416 BYM No 3417 NWLI No 3418 ESND No 3419 LZB No 3420 HDEF No 3421 MBCN No 3422 ESG No 3423 HMY No 3424 BANFP No 3425 MCEF No 3426 CANF No 3427 RNN No 3428 TFX No 3429 ESL No 3430 OTIC No 3431 PFIE No 3432 HA No 3433 HCAC No 3434 OPTN No 3435 LDF No 3436 TG No 3437 SSFN No 3438 CEV No 3439 STK No 3440 FTXL No 3441 GMFL No 3442 MBII No 3443 VIV No 3444 LXRX No 3445 HFWA No 3446 AHT_F No 3447 SMCP No 3448 HPE No 3449 TCF-WS No 3450 MFGP No 3451 TSCO No 3452 ANCX No 3453 MOV No 3454 HRTG No 3455 APTS No 3456 KNX No 3457 TPVG No 3458 EBS No 3459 FMBH No 3460 SP No 3461 ICHR No 3462 TWOW Yes 3463 SFLY No 3464 GTN-A No 3465 ERI No 3466 JNPR No 3467 CLPR No 3468 RNMC No 3469 DIS No 3470 TRCB No 3471 ARCO No 3472 CCL No 3473 MSL No 3474 VRA No 3475 HSIC No 3476 SHIPW No 3477 BOOM No 3478 MHF No 3479 GFI No 3480 AIRI No 3481 HEWU No 3482 GPRK No 3483 ARCC No 3484 MIND No 3485 PACW No 3486 RBCN No 3487 MHO No 3488 FFBCW No 3489 BAC_D No 3490 WLL No 3491 AL No 3492 IGD No 3493 NTES No 3494 USTB No 3495 BRX No 3496 UL No 3497 RGR No 3498 APO No 3499 FTAG No 3500 GS_J No 3501 GDS No 3502 KMPH No 3503 LAWS No 3504 MBVX No 3505 ACSI No 3506 PLCE No 3507 JE_A No 3508 ELLO No 3509 DFBG No 3510 APLS Yes 3511 SPTN No 3512 PRE_G No 3513 ALN No 3514 DEI No 3515 VPV No 3516 SBS No 3517 WYNN No 3518 SNOAW No 3519 CBD No 3520 AUTO No 3521 BLD No 3522 SOR No 3523 JRI No 3524 CNCE No 3525 BPT No 3526 SFST No 3527 JSYNR No 3528 ELF No 3529 HYT No 3530 AIR No 3531 BBW No 3532 AMPH No 3533 CAL No 3534 BXS No 3535 INDB No 3536 CTRE No 3537 CHDN No 3538 LAD No 3539 KDMN No 3540 RICK No 3541 TENX No 3542 TTEC No 3543 SRC No 3544 LOGI No 3545 PBHC No 3546 BOFI No 3547 EACQU No 3548 HBANO No 3549 NVTA No 3550 APPS No 3551 HCOM No 3552 GSBC No 3553 DST No 3554 IZEA No 3555 BLCM No 3556 MNP No 3557 TIER No 3558 TBPH No 3559 FDLO No 3560 PCYG No 3561 FET No 3562 MB No 3563 MOS No 3564 ENRJ No 3565 GSBD No 3566 WIW No 3567 CAMP No 3568 CVU No 3569 AAXN No 3570 CBS-A No 3571 UMH_C No 3572 HTF-CL No 3573 QCRH No 3574 YY No 3575 RES No 3576 QSII No 3577 WING No 3578 POL No 3579 INVA No 3580 ASH No 3581 NWBI No 3582 ITEK No 3583 OCSI No 3584 DAL No 3585 SAFT No 3586 HACV No 3587 JCS No 3588 BRQSW No 3589 UCBI No 3590 FTXG No 3591 BAC_Y No 3592 CSLT No 3593 BWL-A No 3594 IBO No 3595 URBN No 3596 LDOS No 3597 GOVNI No 3598 TEAM No 3599 FFG No 3600 SCE_C No 3601 OLP No 3602 ENTG No 3603 HYDB No 3604 AG No 3605 CYRX No 3606 FNLC No 3607 ISL No 3608 FATE No 3609 GGT_E No 3610 NXEOW No 3611 AGIIL No 3612 RLGT_A No 3613 DDD No 3614 KBWY No 3615 BNED No 3616 ANIP No 3617 PMM No 3618 NXTM No 3619 OILU No 3620 CALA No 3621 CXW No 3622 AE No 3623 ISDR No 3624 MOC No 3625 AC No 3626 VIRC No 3627 RNR_E No 3628 HCAC-WS No 3629 EPD No 3630 BKS No 3631 MYRG No 3632 LEN No 3633 ROST No 3634 NSU No 3635 PDT No 3636 NOV No 3637 BRKR No 3638 MEET No 3639 CRT No 3640 CLNS_G No 3641 PZG No 3642 NEXTW No 3643 UUUU No 3644 MMYT No 3645 TGP_A No 3646 KMX No 3647 GPAC No 3648 STB No 3649 LOGO No 3650 HRTX No 3651 DCIX No 3652 GDV_A No 3653 EDBI No 3654 PTC No 3655 FFTG Yes 3656 NOK No 3657 BANC_E No 3658 NYLD-A No 3659 CNK No 3660 XMX No 3661 UWT No 3662 MYND No 3663 CPF No 3664 PGRE No 3665 NSPR-WS Yes 3666 SODA No 3667 DATA No 3668 EEA No 3669 MTFB No 3670 MCF No 3671 RYTM No 3672 AFH No 3673 OPB No 3674 EMHY No 3675 TRNS No 3676 VRS No 3677 BVN No 3678 CUO No 3679 LYB No 3680 BXMX No 3681 REGI No 3682 YRD No 3683 NXRT No 3684 PBND No 3685 YELP No 3686 GEB No 3687 CYRXW No 3688 HYI No 3689 GD No 3690 ARTX No 3691 NLST No 3692 INSE No 3693 BPMC No 3694 OPTT No 3695 JEQ No 3696 SSB No 3697 MYN No 3698 KRMA No 3699 MVIN No 3700 ASB_D No 3701 EGRX No 3702 LKQ No 3703 GJO No 3704 AAL No 3705 COTY No 3706 SHW No 3707 GEH No 3708 THO No 3709 WFC_P No 3710 DMRI Yes 3711 CLDR No 3712 LOR No 3713 ANH_A No 3714 BCH No 3715 EVSTC No 3716 ADNT No 3717 VCO No 3718 OXM No 3719 GNCA No 3720 EE No 3721 PNC No 3722 FUNC No 3723 PKBK No 3724 SMM No 3725 VNCE No 3726 JOBS No 3727 MYD No 3728 AQ Yes 3729 WEA No 3730 HCRF No 3731 PPG No 3732 PRE_F No 3733 OFG_B No 3734 CORR_A No 3735 TSBK No 3736 XRF No 3737 CHU No 3738 PFNX No 3739 FHN No 3740 TSEM No 3741 HLT No 3742 CLIR No 3743 ATHN No 3744 TTGT No 3745 NOA No 3746 BBF No 3747 MOFG No 3748 NAZ No 3749 SHLO No 3750 MPX No 3751 ARCW No 3752 OSPR Yes 3753 EGO No 3754 INXN No 3755 KEG No 3756 FLGR Yes 3757 ETM No 3758 STRP No 3759 THQ No 3760 ASND No 3761 MIXT No 3762 CDOR No 3763 FLCA Yes 3764 SHEN No 3765 TRQ No 3766 MNI No 3767 JPEU No 3768 CCMP No 3769 PTLC No 3770 CENT No 3771 CYTK No 3772 UPS No 3773 TSRI No 3774 ESSA No 3775 NWSA No 3776 BML_H No 3777 AFI No 3778 USEG No 3779 CCUR No 3780 TIL No 3781 FLDM No 3782 CUR No 3783 KMDA No 3784 MXE No 3785 MENU No 3786 AFTY No 3787 SONC No 3788 AEHR No 3789 ARCI No 3790 PAAS No 3791 FSV No 3792 WRB_D No 3793 NUBD No 3794 TEO No 3795 QUOT No 3796 DGICB No 3797 SIFI No 3798 CORE No 3799 AOD No 3800 OMC No 3801 WBIC No 3802 PHYS No 3803 SMLP No 3804 GGT_B No 3805 BFAM No 3806 ANAT No 3807 TGI No 3808 TDW-WS-A No 3809 DRAD No 3810 FSIC No 3811 FFIN No 3812 ASB No 3813 ARAY No 3814 PAM No 3815 DBD No 3816 HSON No 3817 DYNT No 3818 WFC_J No 3819 VLGEA No 3820 MGRC No 3821 GASX No 3822 PKD No 3823 DDF No 3824 ACNB No 3825 SCAP No 3826 EXAC No 3827 EEFT No 3828 FLR No 3829 SAEX No 3830 MHH No 3831 MWA No 3832 IMRNW No 3833 PBF No 3834 OPGN No 3835 NVEC No 3836 ZNH No 3837 ARCX No 3838 AJX No 3839 MASI No 3840 TRIP No 3841 EDIT No 3842 UBFO No 3843 TCF_B-CL No 3844 GNCMA No 3845 RORE No 3846 SND No 3847 TRCRW Yes 3848 LE No 3849 CMCT No 3850 CRUS No 3851 SDR No 3852 HOLX No 3853 TCX No 3854 DTJ No 3855 RL No 3856 ECPG No 3857 KMPA No 3858 BOLD No 3859 AMOT No 3860 LYTS No 3861 SRCL No 3862 CVV No 3863 ATU No 3864 SM No 3865 CAW No 3866 ZEUS No 3867 SSW_G No 3868 BBN No 3869 ANIK No 3870 SNES No 3871 LPG No 3872 OOMA No 3873 HBAN No 3874 PAH No 3875 CACC No 3876 JPIN No 3877 SAUC No 3878 PUTW No 3879 DXR No 3880 PBDM No 3881 INSW No 3882 TROV No 3883 NVRO No 3884 CHCO No 3885 FLCO No 3886 SBGI No 3887 LXP_C No 3888 FTV No 3889 SMHI No 3890 RVLT No 3891 SNGX No 3892 BRACW No 3893 HYLV No 3894 PSO No 3895 ATTU No 3896 FSBK No 3897 GPOR No 3898 PFFR No 3899 HFBC No 3900 CPA No 3901 ARE_D No 3902 AGI No 3903 SRAX No 3904 FORR No 3905 DPLO No 3906 EBF No 3907 CYAN No 3908 IVR_A No 3909 OCSLL No 3910 ESLT No 3911 NEOG No 3912 CNAC No 3913 AHP No 3914 LJPC No 3915 GOGO No 3916 AWR No 3917 MTL No 3918 ARCH No 3919 BDR No 3920 IGVT No 3921 RCMT No 3922 HIG No 3923 CBAK No 3924 AMGN No 3925 RBS_S No 3926 OSN No 3927 CRESY No 3928 CTZ No 3929 ECOM No 3930 AGRX No 3931 INSY No 3932 PCG_G No 3933 LM No 3934 JHX No 3935 SPTM No 3936 RGT No 3937 NYCB No 3938 PBNC No 3939 FANH No 3940 OMCL No 3941 MRVL No 3942 CIX No 3943 PBYI No 3944 MTB_C Yes 3945 XPO No 3946 HDRW No 3947 WHF No 3948 LQ No 3949 NTX No 3950 VZ No 3951 SLMBP No 3952 FELE No 3953 OBOR No 3954 BFO No 3955 ABT No 3956 WDC No 3957 GTLS No 3958 CPG No 3959 CERN No 3960 TOCA No 3961 GABRW Yes 3962 ULH No 3963 SITO No 3964 CLXT No 3965 NMY No 3966 FSM No 3967 HESM No 3968 BYBK No 3969 JSML No 3970 VR_B No 3971 MH_A No 3972 LUNA No 3973 ABLX No 3974 SMP No 3975 CBL_E No 3976 DUSL No 3977 RF_B No 3978 PIH No 3979 IVFVC No 3980 EHTH No 3981 SABR No 3982 SPG No 3983 FMCIW No 3984 AGGE No 3985 MNTX No 3986 CBX No 3987 MTT No 3988 AGT No 3989 QDEL No 3990 SMIT No 3991 PKO No 3992 BYFC No 3993 JHMU No 3994 GNL No 3995 JHMD No 3996 GLOG No 3997 AGFS No 3998 CMA No 3999 NAII No 4000 GS No 4001 APEI No 4002 WMC No 4003 UZC No 4004 HZN No 4005 MITT_B No 4006 TPHS No 4007 DNOW No 4008 TDY No 4009 TAX No 4010 COLM No 4011 RZA No 4012 HIFS No 4013 WHFBL No 4014 WFC_X No 4015 ANGI No 4016 TWO_B No 4017 INS No 4018 SLCT No 4019 WFC_L No 4020 MAIN No 4021 ARC No 4022 HABT No 4023 SCKT No 4024 WBKC No 4025 DHVW No 4026 LMT No 4027 EVK No 4028 PAGP No 4029 GCH No 4030 HT No 4031 SMI No 4032 DLNG_A No 4033 AHP_B No 4034 VGM No 4035 PUB No 4036 AFGE No 4037 RTIX No 4038 WINA No 4039 PGLC No 4040 ZAIS No 4041 NCS No 4042 EMMS No 4043 RETA No 4044 UWN No 4045 IPG No 4046 AMZA No 4047 SPDN No 4048 FSLR No 4049 JPM No 4050 GECC No 4051 WYY No 4052 VOYA No 4053 CLF No 4054 NCSM No 4055 NGL No 4056 QGTA No 4057 CASS No 4058 QRHC No 4059 ELP No 4060 CPS No 4061 RGC No 4062 EQC_D No 4063 CFNB No 4064 KNDI No 4065 HEBT No 4066 TACO No 4067 AEH No 4068 DEFA No 4069 HD No 4070 MACQ No 4071 XRAY No 4072 FLQH No 4073 SGMA No 4074 BWP No 4075 COMM No 4076 CUBI_D No 4077 FCX No 4078 PRCP No 4079 FMS No 4080 MTEX No 4081 OTEX No 4082 KMF No 4083 ALOT No 4084 GSLC No 4085 PODD No 4086 PMX No 4087 AAP No 4088 FCCO No 4089 TLI No 4090 LEXEB No 4091 DMO No 4092 ZB_G No 4093 CEFS No 4094 SPXV Yes 4095 CHNR No 4096 PSA_A No 4097 LVS No 4098 MZA No 4099 SSW_H No 4100 INOD No 4101 AMPE No 4102 CALX No 4103 CPT No 4104 BURL No 4105 RDFN No 4106 YUMA No 4107 TI-A No 4108 DECK No 4109 ANDE No 4110 SB No 4111 MSF No 4112 AGO_E No 4113 EMP No 4114 JASO No 4115 GSUM No 4116 SUNW No 4117 CATC No 4118 SR No 4119 FSP No 4120 BRG_D No 4121 GDV No 4122 HTBK No 4123 HHYX No 4124 SRCLP No 4125 TU No 4126 MRK No 4127 THG No 4128 GBLIZ No 4129 MSFT No 4130 TS No 4131 WBAI No 4132 MD No 4133 AI_B No 4134 FOX No 4135 FSACU No 4136 TAP-A No 4137 OGE No 4138 MLTI No 4139 CTXS No 4140 CLH No 4141 DM No 4142 PROV No 4143 RDI No 4144 ECCA No 4145 NURE No 4146 SPNS No 4147 DWT No 4148 AGM-A No 4149 AMRN No 4150 FVE No 4151 BGSF No 4152 UNM No 4153 CNACR No 4154 NMFC No 4155 CIZ No 4156 STAG No 4157 YNDX No 4158 FICO No 4159 KTOVW No 4160 ORPN No 4161 NDRA No 4162 FBIO No 4163 STRL No 4164 JPST No 4165 SPXC No 4166 IVR_C No 4167 DPG No 4168 NES No 4169 ADC No 4170 BZH No 4171 FLQG No 4172 SMPLW No 4173 WWE No 4174 ONEO No 4175 ACIA No 4176 DMPI No 4177 CFFI No 4178 CROX No 4179 IPAR No 4180 GUT No 4181 GOODP No 4182 NRP No 4183 EOS No 4184 MCN No 4185 GJT No 4186 PARR No 4187 BDC No 4188 EDI No 4189 CLS No 4190 KRO No 4191 COR No 4192 CHK No 4193 NEXT No 4194 PSMT No 4195 TCFC No 4196 UNTY No 4197 SMG No 4198 BBVA No 4199 AGX No 4200 LTS_A No 4201 PIY No 4202 RSO_C No 4203 PNTR No 4204 STAR_G No 4205 GILT No 4206 CHGG No 4207 CWEB No 4208 BSE No 4209 QTNT No 4210 EPR_E No 4211 FNFV No 4212 DVN No 4213 QXMI No 4214 TNP_B No 4215 BTT No 4216 SEMG No 4217 AVA No 4218 FLC No 4219 SCE_G No 4220 HP No 4221 RP No 4222 ENSG No 4223 CIC-U No 4224 SOJB No 4225 IROQ No 4226 EMBU No 4227 HLF No 4228 VTL No 4229 MTD No 4230 SPKEP No 4231 PHX No 4232 SOVB No 4233 ELU No 4234 NSYS No 4235 KOS No 4236 AME No 4237 PTR No 4238 RCM No 4239 ENR No 4240 MRT No 4241 CDNS No 4242 MCV No 4243 EOI No 4244 BAC_W No 4245 PLXP No 4246 PSDO No 4247 MRTX No 4248 BID No 4249 FSB No 4250 AIB-CL No 4251 JXSB No 4252 PMT_B No 4253 FTNT No 4254 SXT No 4255 SRT No 4256 MS_I No 4257 USOD No 4258 SVBI No 4259 CLUB No 4260 UMH No 4261 PBA No 4262 CMO No 4263 PLUG No 4264 TCRZ No 4265 RSO_A No 4266 CPRT No 4267 MBFI No 4268 INTC No 4269 EYEGW No 4270 BUFF No 4271 I No 4272 ASR No 4273 FFHL No 4274 WTT No 4275 CLSD No 4276 NTRI No 4277 MTZ No 4278 SMMD No 4279 EQFN No 4280 VLY_B No 4281 FB No 4282 EBTC No 4283 DWPP No 4284 AERI No 4285 CPTA No 4286 NBR No 4287 SCHW No 4288 PICO No 4289 TDF No 4290 GYB No 4291 SNFCA No 4292 DBVT No 4293 CEI No 4294 EBR-B No 4295 DRUA No 4296 USCR No 4297 EHIC No 4298 KOR No 4299 WLK No 4300 VAC No 4301 XRX No 4302 APOG No 4303 BGR No 4304 PYN No 4305 ACHN No 4306 HSCZ No 4307 FBMS No 4308 AGO No 4309 GSVC No 4310 WYDE No 4311 MDSO No 4312 FFTY No 4313 RS No 4314 TNET No 4315 PXI No 4316 JLL No 4317 CXRX No 4318 JBSS No 4319 GPIC No 4320 BOKF No 4321 LTM No 4322 EQGP No 4323 TPGH-WS No 4324 WRLSR No 4325 BIOA No 4326 DELTW No 4327 ANTH No 4328 RRD No 4329 MDCA No 4330 NVGN No 4331 ALGT No 4332 OCIP No 4333 KWN No 4334 DMRL No 4335 CGG No 4336 AFSI_A No 4337 MPW No 4338 DEL No 4339 OUSM No 4340 IPAS No 4341 ZEAL No 4342 SB_D No 4343 HMC No 4344 PAG No 4345 BCRH No 4346 NEWR No 4347 RUSHB No 4348 PML No 4349 GRVY No 4350 CNNX No 4351 TM No 4352 KFY No 4353 DAKT No 4354 LFVN No 4355 CENX No 4356 CUBE No 4357 LGF-A No 4358 EQIX No 4359 SEAC No 4360 LTC No 4361 MARK No 4362 PSLV No 4363 SYY No 4364 FIXD No 4365 CTU No 4366 HOS No 4367 MTSI No 4368 MANT No 4369 ABAC No 4370 IFF No 4371 SNH No 4372 VLY-WS No 4373 KSM No 4374 USHY Yes 4375 MVO No 4376 HOTR No 4377 MRBK Yes 4378 PNI No 4379 NSM No 4380 VICR No 4381 ARTW No 4382 MDLX No 4383 STMP No 4384 IGI No 4385 ARDC No 4386 HCAP No 4387 OHGI No 4388 LNC No 4389 ANH No 4390 IGEM Yes 4391 SJM No 4392 MMU No 4393 ARTNA No 4394 MJCO No 4395 HWBK No 4396 KELYB No 4397 INDU No 4398 EA No 4399 ESDIW No 4400 TGEN No 4401 MEDP No 4402 FUV No 4403 HX Yes 4404 BL No 4405 CFCO No 4406 USPH No 4407 STAR_I No 4408 ZN No 4409 WALA No 4410 RWLK No 4411 LB No 4412 CHKE No 4413 TLK No 4414 SNI No 4415 FONR No 4416 TANNI No 4417 COHU No 4418 SBUX No 4419 KOP No 4420 SCE_L No 4421 NMK_C No 4422 DARE No 4423 KN No 4424 FTEO No 4425 MARPS No 4426 EWSC No 4427 VBTX No 4428 KST No 4429 CHL No 4430 CGNX No 4431 SSC No 4432 NIE No 4433 MHD No 4434 FHB No 4435 TAIL No 4436 SGH No 4437 CMT No 4438 VRAY No 4439 MOBL No 4440 SIX No 4441 PMD No 4442 IBIO No 4443 ENIA No 4444 STRM No 4445 AFSI_D No 4446 TPGH No 4447 CCU No 4448 IDTI No 4449 JHMH No 4450 NYH No 4451 MLVF No 4452 AIRG No 4453 JHMC No 4454 MFA No 4455 TVE No 4456 TRK No 4457 NATI No 4458 MATR No 4459 EVG No 4460 SLP No 4461 XRM No 4462 OTIV No 4463 CHMA No 4464 SBNA No 4465 TPB No 4466 PSA_B No 4467 BABY No 4468 FCAL No 4469 PPSI No 4470 MGEN No 4471 UBRT No 4472 TBK No 4473 UCTT No 4474 OMP No 4475 WHLM No 4476 BBD No 4477 SBOW No 4478 BJZ No 4479 VEACU No 4480 BIP No 4481 AFC No 4482 ALT No 4483 D No 4484 UMC No 4485 CNIT No 4486 KIDS No 4487 EMXC No 4488 ULBI No 4489 SHLM No 4490 VBND No 4491 RVT No 4492 NCV No 4493 CYTXW No 4494 ANDV No 4495 AVAL No 4496 STLRU No 4497 TSLX No 4498 ENG No 4499 SBAC No 4500 HUBS No 4501 CCD No 4502 SSKN No 4503 JOE No 4504 FRC_D No 4505 VVI No 4506 MMLP No 4507 RNWK No 4508 GIFI No 4509 MSB No 4510 ULTA No 4511 COF_P No 4512 KMPR No 4513 SEAS No 4514 OMNT No 4515 ICOW No 4516 BMLA No 4517 VNOM No 4518 KIM_J No 4519 WBIY No 4520 FFTI No 4521 BTU_ No 4522 SLGN No 4523 BFIN No 4524 USNA No 4525 GTYHW No 4526 ARGX No 4527 ATNM No 4528 RH No 4529 BSRR No 4530 ACAD No 4531 ELJ No 4532 STL_A No 4533 THST No 4534 TNAV No 4535 BTX-WS No 4536 SUM No 4537 FSAC No 4538 RARX No 4539 BKYI No 4540 SBFGP No 4541 LSBK No 4542 IDA No 4543 SRCE No 4544 RYAAY No 4545 CNC No 4546 AUO No 4547 WIT No 4548 SFBC No 4549 TAL No 4550 BAC_E No 4551 RCS No 4552 ONVO No 4553 INPX No 4554 NTB No 4555 EVHC No 4556 PFIS No 4557 CDR No 4558 WPZ No 4559 MIK No 4560 BIOC No 4561 SSWA No 4562 LXFT No 4563 ESQ No 4564 SMMV No 4565 RNGR No 4566 RLH No 4567 SGY-WS No 4568 VYMI No 4569 NOM No 4570 DRIO No 4571 EQCO No 4572 ICSH No 4573 USLB No 4574 JHG No 4575 IFN No 4576 CSGS No 4577 LGI No 4578 JPHY No 4579 SRTS No 4580 BTX No 4581 SGRP No 4582 HLS No 4583 GSM No 4584 SCCO No 4585 AGCO No 4586 COE No 4587 RNDM No 4588 WES No 4589 MSI No 4590 OPY No 4591 JJSF No 4592 MICT No 4593 MOG-A No 4594 CIO_A No 4595 ORM No 4596 WTRX No 4597 SVU No 4598 OACQ No 4599 CYOU No 4600 SGOC No 4601 NRO No 4602 SSNT No 4603 BNJ No 4604 USAP No 4605 SENEB No 4606 JPHF No 4607 EVOK No 4608 LEU No 4609 VMO No 4610 MS_G No 4611 EWBC No 4612 PK No 4613 GENC No 4614 HURC No 4615 MTR No 4616 EVP No 4617 MNOV No 4618 NXST No 4619 CSPI No 4620 RDN No 4621 ZION No 4622 NHF No 4623 SPEX No 4624 PLYA No 4625 TAPR No 4626 PRGX No 4627 WPRT No 4628 HEP No 4629 BBK No 4630 SQBG No 4631 OPP No 4632 NKTR No 4633 GFED No 4634 IGA No 4635 FENG No 4636 CH No 4637 PHII No 4638 IVC No 4639 FUL No 4640 ESV No 4641 JRO No 4642 SSP No 4643 LITB No 4644 EGAN No 4645 SVVC No 4646 SELF No 4647 SWJ No 4648 FMCIR No 4649 AMCA No 4650 CRR No 4651 ONCE No 4652 GPN No 4653 AQMS No 4654 SASR No 4655 IYLD No 4656 RILY No 4657 MESO No 4658 SPR No 4659 CASC No 4660 NMIH No 4661 HDNG No 4662 DMB No 4663 EW No 4664 HACK No 4665 IRLR Yes 4666 RSLS No 4667 ENFC No 4668 ULVM No 4669 NWL No 4670 ALO No 4671 BCRX No 4672 VST No 4673 OXLC No 4674 IVFGC No 4675 MANU No 4676 NSEC No 4677 FVAL No 4678 NEWS No 4679 XUSA No 4680 KBWD No 4681 BTU No 4682 SE No 4683 AON No 4684 FLGB Yes 4685 PDP No 4686 LEAD No 4687 LMFA No 4688 WTR No 4689 IT No 4690 MPAA No 4691 CBU No 4692 VALU No 4693 UBP No 4694 SHAK No 4695 MPWR No 4696 CALI No 4697 IMOS No 4698 UNB No 4699 SYNT No 4700 VMC No 4701 AAV No 4702 PCG No 4703 GBT No 4704 REDU No 4705 IBCP No 4706 UFI No 4707 CSQ No 4708 CPTAG No 4709 AMZN No 4710 UCBA No 4711 MS No 4712 SGZA No 4713 BTE No 4714 BTZ No 4715 CBB_B No 4716 LFGR No 4717 TWNK No 4718 HFXJ No 4719 PANW No 4720 EIO No 4721 ALP_O-CL No 4722 ATRC No 4723 FBNC No 4724 ACET No 4725 NVO No 4726 AMOV No 4727 PTMC No 4728 HTFA No 4729 VEDL No 4730 UNIT No 4731 CTIB No 4732 EFSC No 4733 GPC No 4734 MMI No 4735 DOC No 4736 MYOK No 4737 BDSI No 4738 CULP No 4739 AAPL No 4740 WFC_V No 4741 ISIG No 4742 AHL No 4743 PDLB No 4744 DWSN No 4745 PNM No 4746 INFY No 4747 NX No 4748 GEO No 4749 AMH_C No 4750 HRS No 4751 VIAB No 4752 CVNA No 4753 KYN_F No 4754 GDI No 4755 HAYN No 4756 AGLE No 4757 FLQM No 4758 LTEA No 4759 ROG No 4760 CTT No 4761 NSA_A No 4762 ENVA No 4763 LDL No 4764 OSPRU No 4765 BSJN No 4766 AMLX No 4767 XONE No 4768 SAR No 4769 GCBC No 4770 HEWC No 4771 FOLD No 4772 NIHD No 4773 DDR No 4774 GEF No 4775 INN_B No 4776 NEOS No 4777 KED No 4778 OXFD No 4779 WBS_E No 4780 WPG No 4781 LQDT No 4782 GLW No 4783 ACHC No 4784 AGC No 4785 IVLU No 4786 CUBI_E No 4787 CLVS No 4788 BOTZ No 4789 PSA_C No 4790 KF No 4791 NVCN No 4792 EXEL No 4793 BRO No 4794 FIG No 4795 RGNX No 4796 NXPI No 4797 CQH No 4798 MMS No 4799 HHC No 4800 FBC No 4801 A No 4802 KMG No 4803 TPIV No 4804 HTGC No 4805 CLMT No 4806 LAYN No 4807 EQT No 4808 STRA No 4809 GMRE No 4810 LPSN No 4811 FLEU No 4812 CAH No 4813 CMSSW Yes 4814 AAMC No 4815 AGIO No 4816 CETV No 4817 TPYP No 4818 ATRO No 4819 SHPG No 4820 EXLS No 4821 MNE No 4822 FBK No 4823 THS No 4824 BVSN No 4825 PIR No 4826 GGT No 4827 NRE No 4828 FGP No 4829 IDLB No 4830 EDU No 4831 AYR No 4832 STOT No 4833 BPFH No 4834 WPG_H No 4835 CHKP No 4836 CWS No 4837 BG No 4838 ALL No 4839 NLSN No 4840 SMBC No 4841 JBR No 4842 OESX No 4843 BAK No 4844 OILK No 4845 GEK No 4846 ASIX No 4847 RY_S-CL No 4848 GDL No 4849 WEBK No 4850 ENBL No 4851 DVD No 4852 OSB No 4853 ICFI No 4854 EBMT No 4855 HLTH No 4856 CAE No 4857 PKW No 4858 PFPT No 4859 VNO_K No 4860 DHT No 4861 ETW No 4862 FLQD No 4863 SGEN No 4864 IAGG No 4865 LXFR No 4866 FTXR No 4867 W No 4868 HMHC No 4869 CVM No 4870 RGLD No 4871 COLB No 4872 WYN No 4873 JGH No 4874 AZUL No 4875 DNP No 4876 LPLA No 4877 EUFL No 4878 NEE_J No 4879 IHIT No 4880 NEU No 4881 TCPC No 4882 TCGP No 4883 NITE No 4884 CIVI No 4885 NDAQ No 4886 HYACU No 4887 GDOT No 4888 IIIN No 4889 CASH No 4890 FRGI No 4891 CASY No 4892 PPHM No 4893 FC No 4894 ANDAU No 4895 EDUC No 4896 LITE No 4897 AUG No 4898 AMT_B No 4899 GSEU No 4900 BF-A No 4901 APPN No 4902 LHCG No 4903 CPLA No 4904 RTK No 4905 DIVB Yes 4906 CBSHP No 4907 BRK-B No 4908 KEN No 4909 URGN No 4910 ESGU No 4911 EXA No 4912 VSI No 4913 NTP No 4914 ROSEU No 4915 TRI No 4916 TRIB No 4917 CVE No 4918 CHMG No 4919 MRDNW No 4920 WTW No 4921 PGP No 4922 FRT No 4923 SGA No 4924 WERN No 4925 SBLKL No 4926 MT No 4927 VICL No 4928 VIRT No 4929 MTNB No 4930 EMKR No 4931 GPRO No 4932 FCAU No 4933 JW-B No 4934 UTL No 4935 QVM No 4936 NGS No 4937 CMSSR Yes 4938 ALP_Q No 4939 CID No 4940 ASYS No 4941 SUPV No 4942 BKSC No 4943 NCOM No 4944 CTAA No 4945 MOSC-U No 4946 EAGLW No 4947 POT No 4948 AROW No 4949 OPHC No 4950 OAKS No 4951 VKQ No 4952 NEXA No 4953 OKE No 4954 DEMG No 4955 LLIT No 4956 AAOI No 4957 TICC No 4958 DIVA No 4959 MTL_ No 4960 GWRE No 4961 BSJO No 4962 WUBA No 4963 PJT No 4964 PXS No 4965 PLOW No 4966 IMH No 4967 PEI_D No 4968 ALLY No 4969 FAC No 4970 BAX No 4971 SPE No 4972 LBTYB No 4973 FLS No 4974 BKCC No 4975 DAIO No 4976 DBIT No 4977 ACERW No 4978 CMS_B No 4979 IPAY No 4980 ALL_D No 4981 RE No 4982 QVCA No 4983 CLNS_E No 4984 BLDP No 4985 MRUS No 4986 LUB No 4987 COMB No 4988 ODC No 4989 PANL No 4990 APDN No 4991 XELB No 4992 ISZE No 4993 CIBR No 4994 AUY No 4995 NOMD No 4996 PH No 4997 CSIQ No 4998 NTRP No 4999 CCI_A No 5000 STAR No 5001 KFFB No 5002 MBI No 5003 EL No 5004 CRAY No 5005 CHAD No 5006 GSH No 5007 VOC No 5008 TRNC No 5009 CVTI No 5010 BECN No 5011 GSSC No 5012 LEDS No 5013 DSW No 5014 TVPT No 5015 DDBI No 5016 RLJ_A No 5017 MNR_C No 5018 ZKIN No 5019 NYMTN No 5020 NTRA No 5021 NCZ No 5022 HCKT No 5023 NUAG No 5024 BHP No 5025 RBIN No 5026 TGT No 5027 PCOM No 5028 FCEL No 5029 DTF No 5030 ASTC No 5031 PFS No 5032 BBBY No 5033 NMK_B No 5034 KTOV No 5035 RMT No 5036 BEN No 5037 IX No 5038 BSF No 5039 ANDAR No 5040 IBKCP No 5041 CPSS No 5042 FT No 5043 BPY No 5044 SPUN No 5045 BOJA No 5046 CSFL No 5047 MED No 5048 WSR No 5049 HAS No 5050 CVCY No 5051 DIAX No 5052 DAN No 5053 SINO No 5054 BSFT No 5055 FINX No 5056 ATGE No 5057 VSAT No 5058 SYKE No 5059 GIGB No 5060 IBTX No 5061 RA No 5062 ACBI No 5063 TCF_D No 5064 INN No 5065 AVY No 5066 KURA No 5067 USAS No 5068 ADXS No 5069 HAL No 5070 MHN No 5071 TRCH No 5072 TAYD No 5073 CASI No 5074 BBDO No 5075 SPAR No 5076 JHMS No 5077 AYI No 5078 RGSE No 5079 GPI No 5080 NMI No 5081 NAN No 5082 NBEV No 5083 LEE No 5084 BMS No 5085 CRS No 5086 CCCL No 5087 DSGX No 5088 CODA No 5089 AIZ No 5090 CHGX No 5091 BGNE No 5092 WPG_I No 5093 TMP No 5094 AOBC No 5095 PNR No 5096 VIGI No 5097 NODK No 5098 PUI No 5099 ETE No 5100 RHE_A No 5101 LVNTA No 5102 CUDA No 5103 LYL No 5104 FTK No 5105 RFCI No 5106 PSTI No 5107 PULM No 5108 UBNK No 5109 DVA No 5110 TLND No 5111 SRPT No 5112 ARES_A No 5113 ZTO No 5114 RELL No 5115 IGLD No 5116 EAE No 5117 HIO No 5118 AP No 5119 SCL No 5120 DNKN No 5121 MIDD No 5122 ADVM No 5123 CMU No 5124 HDP No 5125 LLQD No 5126 CRD-B No 5127 CHCT No 5128 AFT No 5129 PGH No 5130 EFNL No 5131 DEUS No 5132 NWN No 5133 ADS No 5134 QBAK No 5135 ONEV No 5136 BKHU No 5137 IRT No 5138 LVIN No 5139 VMOT No 5140 MMC No 5141 MXL No 5142 GEM No 5143 DRH No 5144 DELT No 5145 DLR_G No 5146 VJET No 5147 WTTR No 5148 STAR_D No 5149 ALGN No 5150 MGYR No 5151 LMAT No 5152 LNC-WS No 5153 NAVB No 5154 DRIOW No 5155 BRAC No 5156 ZB_A No 5157 C_L No 5158 ST No 5159 DDR_K No 5160 PBI_B No 5161 RVRS Yes 5162 MSN No 5163 TILE No 5164 DOVA No 5165 VECO No 5166 ESNT No 5167 SXC No 5168 CARB No 5169 USG No 5170 JPC No 5171 RDWR No 5172 NEWT No 5173 CFG No 5174 CIM_A No 5175 LINK No 5176 DS No 5177 ACLS No 5178 BGI No 5179 GRUB No 5180 AZRX No 5181 COT No 5182 FPEI No 5183 UA No 5184 LRAD No 5185 TRIL No 5186 CAF No 5187 ASCMA No 5188 TDOC No 5189 GLNG No 5190 JMPC No 5191 PKX No 5192 BDX No 5193 WAAS No 5194 WBA No 5195 CIR No 5196 EVBN No 5197 EVOL No 5198 CATB No 5199 QGEN No 5200 PEGI No 5201 AXSM No 5202 CNAT No 5203 AGM_B No 5204 SNHNI No 5205 INDF No 5206 EIX No 5207 RUSHA No 5208 GMS No 5209 EFAX No 5210 GVIP No 5211 RAS_C No 5212 DMF No 5213 TRTN No 5214 GJS No 5215 TSC No 5216 FNSR No 5217 CB No 5218 VKTX No 5219 OVAS No 5220 WMT No 5221 HST No 5222 MRIN No 5223 DORM No 5224 FLIR No 5225 DX No 5226 AGRO No 5227 ARLP No 5228 EMDV No 5229 C_S No 5230 SPSB No 5231 FMI No 5232 CHFN No 5233 AXTA No 5234 AHH No 5235 XCRA No 5236 BFS_C No 5237 FXJP Yes 5238 QHC No 5239 CIG No 5240 CELH No 5241 SPHS No 5242 XGTIW Yes 5243 ALLT No 5244 AR No 5245 DL No 5246 PCK No 5247 ACP No 5248 ECF_A No 5249 ADI No 5250 CLFD No 5251 CBO No 5252 HYLB No 5253 VIVE No 5254 EBAYL No 5255 CYAD No 5256 NVAX No 5257 CYS_A No 5258 SPWH No 5259 BQH No 5260 PLNT No 5261 FMSA No 5262 FISK No 5263 CKX No 5264 ISP-CL No 5265 RECN No 5266 IIPR No 5267 RF_A No 5268 HAHA No 5269 ALBO No 5270 WU No 5271 HIMX No 5272 TARO No 5273 NGHC No 5274 ALK No 5275 BUI No 5276 FSCT Yes 5277 TR No 5278 FIEE No 5279 GLBZ No 5280 CECO No 5281 ESPR No 5282 CCOR No 5283 BLMT No 5284 SMTC No 5285 ALDW No 5286 LXU No 5287 GBX No 5288 NKG No 5289 PSA_D No 5290 SBCF No 5291 BCAC No 5292 AKR No 5293 NTIP No 5294 HTZ No 5295 SFBS No 5296 EVR No 5297 AMNB No 5298 VBLT No 5299 UAA No 5300 AMBCW No 5301 RSG No 5302 GGZRW Yes 5303 FSAM No 5304 CMI No 5305 SPCB No 5306 RXII No 5307 GS_I-CL No 5308 LHO_I No 5309 PRO No 5310 PMOM Yes 5311 ACTA No 5312 TRUE No 5313 BPK No 5314 ONB No 5315 IRDM No 5316 FSFG No 5317 NHTC No 5318 CHEK No 5319 AVD No 5320 CSWI No 5321 BPRN No 5322 PBBI No 5323 MHI No 5324 IOTS No 5325 CRVS No 5326 BWXT No 5327 TDW No 5328 VLY No 5329 NCBS No 5330 CTDD No 5331 EFAS No 5332 USA No 5333 KTP No 5334 JHMM No 5335 SNPS No 5336 COR_A No 5337 MPACU No 5338 ELECU No 5339 FIZZ No 5340 PI No 5341 WETF No 5342 GPS No 5343 HCSG No 5344 FLJH Yes 5345 LEXEA No 5346 JLS No 5347 CLNE No 5348 STI No 5349 SNGXW No 5350 SNP No 5351 TNP_D No 5352 ANAB No 5353 AMSF No 5354 IGHG No 5355 PKY No 5356 AEP No 5357 AMT No 5358 HLX No 5359 NURO No 5360 ESGN No 5361 CFC_B No 5362 ATHM No 5363 JPI No 5364 VLRS No 5365 FRED No 5366 GAB No 5367 ACIU No 5368 OFED No 5369 FFSG Yes 5370 BC No 5371 CFCOW No 5372 LULU No 5373 ETX No 5374 WTIU No 5375 NFJ No 5376 BPMX No 5377 GOEX No 5378 EBR No 5379 MET No 5380 ADBE No 5381 RESI No 5382 USMC No 5383 JHMT No 5384 FLHK Yes 5385 USB_O No 5386 SU No 5387 BML_L No 5388 MTB No 5389 EDD No 5390 BSCR No 5391 PFK No 5392 JSMD No 5393 NNN No 5394 FNTE No 5395 FRAC No 5396 DLR_C No 5397 AMH_D No 5398 FRC_G No 5399 PAHC No 5400 VTEB No 5401 ORI No 5402 CSBR No 5403 BT No 5404 ESXB No 5405 JSD No 5406 MDRX No 5407 NVTR No 5408 BHF No 5409 BPI No 5410 XEL No 5411 CAPR No 5412 JNCE No 5413 BLL No 5414 RENN No 5415 WEAR No 5416 MATW No 5417 QD No 5418 CFBI No 5419 HOFT No 5420 FITB No 5421 COF_D No 5422 TJX No 5423 FLO No 5424 IRBT No 5425 GBL No 5426 ROSEW No 5427 GPMT No 5428 CAFD No 5429 JPM_D-CL Yes 5430 TOPS No 5431 QVAL No 5432 RTRX No 5433 DTLA_ No 5434 FSACW No 5435 UBOH No 5436 IAF No 5437 ENLC No 5438 WPM No 5439 NEE_H-CL No 5440 DISCK No 5441 ETSY No 5442 KYN No 5443 EMBH No 5444 JPM-WS No 5445 FIS No 5446 ABR_B No 5447 SOHOM No 5448 ALSN No 5449 JTPY No 5450 GSK No 5451 JMT No 5452 AINV No 5453 CBRL No 5454 VERI No 5455 GATX No 5456 CRBP No 5457 BORN No 5458 SLD No 5459 CLNS_H No 5460 SMIN No 5461 RFIL No 5462 MQT No 5463 OII No 5464 CF No 5465 AMAT No 5466 HEAR No 5467 HCC No 5468 BRGL No 5469 AMN No 5470 ESIO No 5471 LOW No 5472 ZF No 5473 VNRX No 5474 KIRK No 5475 HOLI No 5476 LVHE No 5477 BSD No 5478 LEO No 5479 WIA No 5480 APDNW No 5481 RGCO No 5482 PTN No 5483 CUK No 5484 DQ No 5485 VSDA No 5486 MMM No 5487 AXE No 5488 MER_P No 5489 FR No 5490 MET_A No 5491 EROS No 5492 CL No 5493 KTOS No 5494 FTRPR No 5495 JILL No 5496 ECCZ No 5497 VR No 5498 AKTX No 5499 NP No 5500 ASPS No 5501 HMNY No 5502 HAWX No 5503 HI No 5504 HYB No 5505 DTUL Yes 5506 EQBK No 5507 CPRX No 5508 NESRW No 5509 SALM No 5510 HOMB No 5511 AXS_D No 5512 IBOC No 5513 JCAP No 5514 AGII No 5515 MYE No 5516 EOT No 5517 SCVL No 5518 EXP No 5519 ABCO No 5520 MKL No 5521 SCHW_B-CL Yes 5522 INB No 5523 MNR No 5524 VBF No 5525 ATV No 5526 T No 5527 SMMT No 5528 SAN No 5529 INSI No 5530 CVCO No 5531 FRA No 5532 DE No 5533 CHMI_A No 5534 UVV No 5535 EPR_F No 5536 KEYS No 5537 DCM No 5538 PTCT No 5539 TRCO No 5540 DEST No 5541 JRS No 5542 MSBI No 5543 GWW No 5544 IID No 5545 HEI-A No 5546 ALRN No 5547 FWONA No 5548 ABR No 5549 HJPX No 5550 ANCB No 5551 DZSI No 5552 RYN No 5553 ATAX No 5554 EVI No 5555 APLE No 5556 USAT No 5557 CVRS No 5558 JAX No 5559 CMP No 5560 TCCA No 5561 BLH No 5562 HXL No 5563 ADP No 5564 SQZZ No 5565 BWINA No 5566 EC No 5567 TSN No 5568 AFGH No 5569 JKHY No 5570 DMLP No 5571 EXIV No 5572 GLOP_A No 5573 O No 5574 MSP No 5575 GSHTU No 5576 PAR No 5577 BKU No 5578 EMI No 5579 ONTXW No 5580 IPGP No 5581 JPEH No 5582 IMDZ No 5583 ARKK No 5584 NUM No 5585 BLHY No 5586 SDLP No 5587 PF No 5588 ECCY No 5589 CRHM No 5590 PAYC No 5591 PED No 5592 ACGLP No 5593 HBANN No 5594 MUX No 5595 HT_D No 5596 FORK No 5597 CNYA No 5598 VEACW No 5599 BBGI No 5600 COM No 5601 CIM No 5602 CTRV No 5603 IBUY No 5604 QADB No 5605 SAN_B No 5606 BME No 5607 IRTC No 5608 ABEO No 5609 MXC No 5610 DISH No 5611 XEC No 5612 EVLV No 5613 COL No 5614 NXTD No 5615 GOGL No 5616 ECOL No 5617 WTM No 5618 TDA No 5619 VKI No 5620 DOTAU No 5621 SRG No 5622 CGO No 5623 SREV No 5624 ALDR No 5625 EVH No 5626 CSU No 5627 DG No 5628 EXTR No 5629 JEMD No 5630 ZTR No 5631 GLOB No 5632 GNE_A No 5633 SHIP No 5634 CVLT No 5635 CHSCL No 5636 UBP_H No 5637 ASB-WS No 5638 VER No 5639 APOPW No 5640 FCPT No 5641 GMRE_A No 5642 CRTO No 5643 CLBS No 5644 UONEK No 5645 ZGNX No 5646 MFINL No 5647 KHC No 5648 XPER No 5649 VTR No 5650 COF_G No 5651 RNP No 5652 CONN No 5653 GUT_A No 5654 EXG No 5655 OVBC No 5656 POLA No 5657 ZBRA No 5658 WFC_Q No 5659 HNP No 5660 NTGR No 5661 AVIR No 5662 PAA No 5663 SWX No 5664 GAINM No 5665 PPIH No 5666 NGHCZ No 5667 DGLY No 5668 ISD No 5669 EIM No 5670 DBRT Yes 5671 ATXI No 5672 AUMN No 5673 EAB No 5674 GHY No 5675 NMZ No 5676 SRUNW No 5677 PRTA No 5678 ACY No 5679 BKH No 5680 DHF No 5681 LEA No 5682 TKC No 5683 WSTG No 5684 MBFIP No 5685 LN No 5686 RARE No 5687 CISN-WS Yes 5688 RTN No 5689 H No 5690 CART No 5691 DYN_A No 5692 SLM No 5693 LCAHU No 5694 AXP No 5695 PSA_U No 5696 NPV No 5697 CALF No 5698 AZN No 5699 CLSN No 5700 GBDC No 5701 TOUR No 5702 MQY No 5703 TYG No 5704 MITK No 5705 TPGH-U No 5706 UAMY No 5707 RLJE No 5708 BCLI No 5709 RELX No 5710 SPDW No 5711 SWNC No 5712 MRNS No 5713 MRTN No 5714 DTRM No 5715 ELMD No 5716 NSPR-WS-B Yes 5717 UQM No 5718 RBPAA No 5719 NBB No 5720 DVCR No 5721 CHE No 5722 BBT_H No 5723 XELA No 5724 MILN No 5725 CMA-WS No 5726 MAXR No 5727 VHI No 5728 GME No 5729 CBAN No 5730 MLNX No 5731 PRKR No 5732 SHLDW No 5733 NVCR No 5734 ACRE No 5735 BLFS No 5736 JPGB No 5737 NDRM No 5738 IDSY No 5739 AVNW No 5740 VRNS No 5741 CHSCN No 5742 MEIP No 5743 MATX No 5744 SCAC No 5745 PTGX No 5746 HSTM No 5747 DEMS No 5748 CMCL No 5749 SHSP No 5750 TBB Yes 5751 DNN No 5752 SJR No 5753 JPM_D No 5754 PMT No 5755 AKO-B No 5756 KAP No 5757 EBIO No 5758 JAGX No 5759 ENJ No 5760 NEE_C No 5761 FOF No 5762 UAL No 5763 TREX No 5764 RAS No 5765 CFO No 5766 SMTX No 5767 EQC No 5768 AMSWA No 5769 TEX No 5770 CISN No 5771 DESP No 5772 INN_D No 5773 VTRB No 5774 CEL No 5775 BDXA No 5776 EP_C No 5777 BGT No 5778 EEMX No 5779 WRLD No 5780 MGNX No 5781 EFX No 5782 CYCCP No 5783 WBC No 5784 L No 5785 DEWJ No 5786 SAP No 5787 HEQ No 5788 BDGE No 5789 MS_E No 5790 CYHHZ No 5791 PCRX No 5792 SUSB No 5793 FUT No 5794 LIVE No 5795 GLBL No 5796 PCI No 5797 PTI No 5798 WHR No 5799 GGO_A No 5800 SMHD No 5801 KIOR No 5802 ITCI No 5803 LKSD No 5804 FIBR No 5805 CTX No 5806 INFI No 5807 EWMC No 5808 FPAY No 5809 TOWR No 5810 ELLI No 5811 RAD No 5812 HK No 5813 ISTR No 5814 GAINO No 5815 CREE No 5816 WBID No 5817 EBSB No 5818 UTSI No 5819 HIL No 5820 HRC No 5821 CIB No 5822 JMU No 5823 ACGLO No 5824 JUNO No 5825 NBIX No 5826 MPCT No 5827 SHAG No 5828 MU No 5829 WTBA No 5830 CADC No 5831 VAMO No 5832 RDNT No 5833 LPNT No 5834 VNET No 5835 BP No 5836 ISRG No 5837 PEB No 5838 KBLMW No 5839 MLI No 5840 XBKS No 5841 NXEOU No 5842 VMAX No 5843 BSTI No 5844 IDMO No 5845 EXR No 5846 VSTM No 5847 JETS No 5848 SPRT No 5849 SIM No 5850 SFIG No 5851 UUUU-WS No 5852 NICK No 5853 AFSI_B No 5854 APA No 5855 TNP No 5856 GFA No 5857 FFIV No 5858 TREE No 5859 AIW No 5860 SGMS No 5861 SBPH No 5862 BHACU Yes 5863 BF-B No 5864 MCB Yes 5865 NFLT No 5866 OFG No 5867 BIO No 5868 VNTV No 5869 TSM No 5870 PIM No 5871 BSBR No 5872 NSH No 5873 OMF No 5874 JPS No 5875 MOH No 5876 AVAV No 5877 BCE No 5878 DGII No 5879 SON No 5880 CBPX No 5881 DISCB No 5882 BANC No 5883 BFS No 5884 NFBK No 5885 AKER No 5886 GCO No 5887 RFAP No 5888 DYSL No 5889 EHI No 5890 SHBI No 5891 GALT No 5892 GILD No 5893 AEY No 5894 DTQ No 5895 CHSCO No 5896 MUH No 5897 RMTI No 5898 HAIR No 5899 ICLR No 5900 AHGP No 5901 POR No 5902 ENPH No 5903 PLAB No 5904 EMX No 5905 SYMC No 5906 LLY No 5907 MYF No 5908 CDC No 5909 AZZ No 5910 ZLAB No 5911 SWM No 5912 TRMB No 5913 GS_D No 5914 WK No 5915 CMS No 5916 GPT_A No 5917 RMCF No 5918 PHM No 5919 K No 5920 ABG No 5921 OACQU Yes 5922 WSCI No 5923 GAB_H No 5924 TTM No 5925 DGSE No 5926 SO No 5927 SFS No 5928 AKAM No 5929 FORM No 5930 HWCC No 5931 DSKE No 5932 Z No 5933 FNWB No 5934 SSW_E No 5935 SNR No 5936 FHN_A No 5937 ZSAN No 5938 INTL No 5939 ALTY No 5940 GOODO No 5941 GPM No 5942 LRET No 5943 MUI No 5944 ALL_A No 5945 PJC No 5946 ROP No 5947 INUV No 5948 NAOV Yes 5949 XINA No 5950 QURE No 5951 KOF No 5952 FMDG No 5953 MITT_A No 5954 TD No 5955 INST No 5956 VNO_G No 5957 LFUS No 5958 ASNA No 5959 NTRS No 5960 MYGN No 5961 MCR No 5962 GDVD No 5963 BNTCW No 5964 RPRX No 5965 MCRN No 5966 RELY No 5967 CXO No 5968 FMHI Yes 5969 GCP No 5970 SGF No 5971 SGYP No 5972 ELS No 5973 UTES No 5974 AGTC No 5975 BJRI No 5976 OCFC No 5977 NUAN No 5978 HNI No 5979 AWI No 5980 WWW No 5981 OPOF No 5982 OXBR No 5983 CVEO No 5984 WEXP No 5985 IHD No 5986 TCRX No 5987 ZYME No 5988 PRTO No 5989 NUW No 5990 EGI No 5991 AKRX No 5992 DTYS No 5993 HTHT No 5994 ABAX No 5995 RNR_C No 5996 CAA No 5997 OGCP No 5998 FDRR No 5999 ENX No 6000 MDLQ No 6001 KKR_B No 6002 SENS No 6003 AGNC No 6004 TYHT No 6005 LAMR No 6006 CLCT No 6007 CACI No 6008 RMR No 6009 ABCB No 6010 WVVI No 6011 MYOS No 6012 CSB No 6013 YERR No 6014 OILB No 6015 TMUSP No 6016 CBMG No 6017 SRI No 6018 EVGN No 6019 PETS No 6020 GALE No 6021 AIG-WS No 6022 CMCO No 6023 HAUD No 6024 AGNCN No 6025 FLXN No 6026 MCHX No 6027 OMER No 6028 MPC No 6029 WFE_A No 6030 BZM No 6031 AMTD No 6032 PHIIK No 6033 KNL No 6034 RBB No 6035 TY No 6036 PSA_W No 6037 C No 6038 SOHU No 6039 ABBV No 6040 ZBZX No 6041 PBR-A No 6042 UBSI No 6043 PRTK No 6044 ACM No 6045 VCV No 6046 IPI No 6047 URI No 6048 WIX No 6049 SAMG No 6050 TXN No 6051 CLRBZ No 6052 CC No 6053 AAME No 6054 EMAN No 6055 EURZ No 6056 STT_C No 6057 PCBK No 6058 TNK No 6059 APT No 6060 EME No 6061 MDVX No 6062 THR No 6063 AKAO No 6064 ARI No 6065 FQAL No 6066 GCV No 6067 PRK No 6068 ITUB No 6069 MDXG No 6070 ALXN No 6071 GPJA No 6072 SPAB No 6073 ARII No 6074 DCUD No 6075 GMO No 6076 AMBC No 6077 PCO No 6078 DVMT No 6079 NHS No 6080 REGN No 6081 AHL_D No 6082 MIY No 6083 MSDI No 6084 CAVM No 6085 PRTS No 6086 GXP No 6087 STBA No 6088 PFBX No 6089 ESES No 6090 TSG No 6091 NJR No 6092 LNGR No 6093 TTPH No 6094 OBE No 6095 XOM No 6096 UFPT No 6097 ARKR No 6098 ABUS No 6099 ARKG No 6100 HBMD No 6101 SACH No 6102 SRNE No 6103 DOX No 6104 RUN No 6105 ALIM No 6106 CCC No 6107 BKI No 6108 MNKD No 6109 CBB No 6110 CRAK No 6111 BNSO No 6112 GS_K No 6113 CRC No 6114 BBT_G No 6115 NAD No 6116 TRGP No 6117 RFEM No 6118 BR No 6119 CEY No 6120 NM_H No 6121 MOTI No 6122 HOV No 6123 PCH No 6124 SRCI No 6125 PBCTP No 6126 FRSH No 6127 ROX No 6128 ACSF No 6129 ONVI No 6130 FULT No 6131 TWN No 6132 RSPP No 6133 DFNL No 6134 RTEC No 6135 AGM_A No 6136 SMED No 6137 STC No 6138 CHSCP No 6139 NBH No 6140 ALG No 6141 EBAY No 6142 BITA No 6143 LTXB No 6144 GGZ No 6145 ANF No 6146 XIN No 6147 NXN No 6148 GLV No 6149 GROW No 6150 KIQ No 6151 HYXU No 6152 C_C No 6153 MDR No 6154 OCIO No 6155 LPTH No 6156 SRUN No 6157 MMDMR No 6158 FNB No 6159 SKT No 6160 OPHT No 6161 CS No 6162 CTRP No 6163 SOHO No 6164 GLO No 6165 AMD No 6166 NUDM No 6167 SSTI No 6168 FOANC No 6169 AM No 6170 ROSG No 6171 FFNW No 6172 FRTA No 6173 SGQI No 6174 GRR No 6175 EUXL No 6176 GENE No 6177 OSTK No 6178 WD No 6179 BCACU No 6180 PACB No 6181 SCS No 6182 SXCP No 6183 MRDN No 6184 XOXO No 6185 OSUR No 6186 TXT No 6187 TSQ No 6188 DNBF No 6189 JAKK No 6190 ROGS No 6191 NBL No 6192 OAKS_A No 6193 KBR No 6194 ESGS No 6195 EVAR No 6196 USB_M No 6197 CIG-C No 6198 IPOA-WS No 6199 ADRO No 6200 BML_J No 6201 AKG No 6202 MYC No 6203 GRP-U No 6204 WFC_Y No 6205 NEOT No 6206 GIS No 6207 UTX No 6208 CAAS No 6209 VSTO No 6210 GDP No 6211 EDF No 6212 SCA No 6213 KOPN No 6214 BTG No 6215 USDP No 6216 MATF No 6217 NTCT No 6218 PCLN No 6219 ECF No 6220 MAYS No 6221 LTRPA No 6222 MTCH No 6223 DUKH No 6224 STT_D No 6225 FRT_C No 6226 CPIX No 6227 CODI No 6228 FOGO No 6229 CARO No 6230 LIND No 6231 HNNA No 6232 STAF No 6233 UNVR No 6234 PDCE No 6235 ACMR Yes 6236 HMSY No 6237 WLB No 6238 WMS No 6239 PIZ No 6240 HTY No 6241 CLX No 6242 IRET_C No 6243 XYL No 6244 BTN No 6245 WPC No 6246 TTWO No 6247 ARR No 6248 CSML No 6249 ADUS No 6250 EFOI No 6251 DYB No 6252 LGF-B No 6253 IMTB No 6254 MEI No 6255 CWAI No 6256 RNST No 6257 UEVM No 6258 MUA No 6259 EIG No 6260 CNACW No 6261 ACER No 6262 IEX No 6263 HEUS No 6264 BAC_A No 6265 SXE No 6266 GRX_A No 6267 AKCA No 6268 KGRN No 6269 USB_H No 6270 AEUA No 6271 EDGW No 6272 INSM No 6273 CXP No 6274 GNUS No 6275 C_P No 6276 REX No 6277 PUK_ No 6278 BK_C No 6279 CREG No 6280 ISCA No 6281 PBPB No 6282 EFBI No 6283 PCG_H No 6284 CII No 6285 MODN No 6286 TSE No 6287 ICL No 6288 TSLA No 6289 BOTJ No 6290 SPOK No 6291 AIC No 6292 PDI No 6293 FMCI No 6294 INFO No 6295 TX No 6296 SBI No 6297 FCVT No 6298 MPACW No 6299 COGT No 6300 APWC No 6301 FARM No 6302 NUEM No 6303 DYN-WS-A No 6304 AMID No 6305 COWNL No 6306 XL No 6307 RBC No 6308 GGN_B No 6309 UMBF No 6310 BIT No 6311 NRG No 6312 OXBRW No 6313 HFXE No 6314 IQI No 6315 ATKR No 6316 PAI No 6317 PEP No 6318 NWFL No 6319 NBTB No 6320 IKNX No 6321 ITRI No 6322 CCRN No 6323 RY No 6324 ADOM No 6325 CPE No 6326 BSL No 6327 PSA_X No 6328 CIVBP No 6329 GLPG No 6330 AEZS No 6331 PSMM No 6332 AIN No 6333 QQQX No 6334 ETMW Yes 6335 GRC No 6336 EVLMC No 6337 RDC No 6338 BRG No 6339 STNLU Yes 6340 CHY No 6341 AXS_E No 6342 QSR No 6343 EIV No 6344 RICE No 6345 SPN No 6346 VEON No 6347 FRPT No 6348 BPTH No 6349 RCON No 6350 RCOM No 6351 BNTC No 6352 HIHO No 6353 SN No 6354 NYMX No 6355 QTRH No 6356 SGB No 6357 UEIC No 6358 WHG No 6359 ASG No 6360 WGL No 6361 UG No 6362 BRACR Yes 6363 CIK No 6364 OFG_A No 6365 BXC No 6366 PPC No 6367 PTSI No 6368 MTSC No 6369 ANH_B No 6370 NICE No 6371 UFCS No 6372 AFAM No 6373 VTGN No 6374 UNP No 6375 ARCB No 6376 BSCP No 6377 ENIC No 6378 MDCO No 6379 CCM No 6380 PEN No 6381 JWN No 6382 BSMX No 6383 NAP No 6384 PPHMP No 6385 RZB No 6386 OCUL No 6387 KMB No 6388 SKLN No 6389 VCF No 6390 AAON No 6391 LCI No 6392 RAVE No 6393 KLXI No 6394 LPT No 6395 DAX No 6396 VLO No 6397 DVAX No 6398 SSY No 6399 MOD No 6400 SNY No 6401 AINC No 6402 B No 6403 SBOT No 6404 GDV_D No 6405 SCYX No 6406 CSCO No 6407 BIVV No 6408 OLLI No 6409 PEBO No 6410 KRYS No 6411 ZBIO No 6412 PTLA No 6413 NMS No 6414 PES No 6415 GPE_A-CL No 6416 CELC No 6417 ASM No 6418 GST_B No 6419 SUI No 6420 CHRS No 6421 NEON No 6422 DXB No 6423 C_N No 6424 YORW No 6425 LGCYO No 6426 SOFO No 6427 AHL_C No 6428 SCHL No 6429 OHI No 6430 TECD No 6431 NEWA No 6432 GHM No 6433 CMTL No 6434 CYRN No 6435 AFG No 6436 IRET_B-CL No 6437 TLYS No 6438 MXWL No 6439 DXUS No 6440 COF No 6441 UTLF No 6442 PCG_C No 6443 JHY No 6444 MOMO No 6445 CLDX No 6446 SCX No 6447 NTG No 6448 BRK-A No 6449 RCKY No 6450 AMH_E No 6451 ETO No 6452 SYNA No 6453 CW No 6454 ESCA No 6455 MMIT Yes 6456 HRI No 6457 FLAT No 6458 MOG-B No 6459 GSHTW No 6460 LINDW No 6461 CDE No 6462 SLRC No 6463 ERII No 6464 TST No 6465 CTAS No 6466 EARS No 6467 ASA No 6468 DERM No 6469 DWLD No 6470 CHUY No 6471 VRML No 6472 HMLP_A No 6473 AFL No 6474 OLED No 6475 OKSB No 6476 LAKE No 6477 NEP No 6478 ZG No 6479 RPXC No 6480 CWH No 6481 IDT No 6482 FEDU Yes 6483 DESC No 6484 SPSM No 6485 MUC No 6486 PBH No 6487 PLPM No 6488 QUAD No 6489 BST No 6490 KFN_ No 6491 UDBI No 6492 USOU No 6493 AEMD No 6494 ARQL No 6495 SSWN No 6496 CAMT No 6497 JSM No 6498 NMRX No 6499 CYCC No 6500 HES_A No 6501 NSPR No 6502 JBT No 6503 FCFS No 6504 COWN No 6505 NGHCO No 6506 BTI No 6507 CBI No 6508 CHSCM No 6509 HUSV No 6510 AWK No 6511 BHGE No 6512 STLRW No 6513 SAH No 6514 USFD No 6515 NAK No 6516 ITGR No 6517 VG No 6518 CLDC No 6519 GRIF No 6520 GGM No 6521 GNW No 6522 VZA No 6523 EPE No 6524 MCS No 6525 PNC_Q No 6526 RACE No 6527 BXMT No 6528 MVIS No 6529 PMO No 6530 EAI No 6531 PPX No 6532 M No 6533 PDM No 6534 MMSI No 6535 GLDD No 6536 HMN No 6537 MZF No 6538 TSI No 6539 DXTR No 6540 IGEB No 6541 FARO No 6542 CSF No 6543 EURN No 6544 GRFS No 6545 CWCO No 6546 REML No 6547 OAK No 6548 WKHS No 6549 RVP No 6550 PETX No 6551 MNST No 6552 CTSH No 6553 CMG No 6554 SCHW_C No 6555 EOCC No 6556 DCT No 6557 VISI No 6558 IESC No 6559 GPP No 6560 CBL_D No 6561 KVHI No 6562 MS_K No 6563 BMA No 6564 EARN No 6565 STOR No 6566 HEWW No 6567 FNTEW No 6568 TLP No 6569 ARNA No 6570 NFX No 6571 GCI No 6572 HSBC No 6573 FWONK No 6574 MSFG No 6575 FCNCA No 6576 GNL_A No 6577 CDR_B No 6578 MAA_I No 6579 SFE No 6580 BWG No 6581 CTB No 6582 OHAI No 6583 GRF No 6584 ESRX No 6585 VTN No 6586 OCN No 6587 EEMO No 6588 MPO No 6589 MACQW No 6590 ESEA No 6591 BLES No 6592 VYGR No 6593 NATR No 6594 SWP No 6595 JBL No 6596 ABCD No 6597 CIDM No 6598 HTGX No 6599 CBLI No 6600 XBIT No 6601 CWT No 6602 HAIN No 6603 CNDT No 6604 IDHD No 6605 GM No 6606 CAPL No 6607 CIC No 6608 NQ No 6609 PFE No 6610 AN No 6611 HYGS No 6612 KWR No 6613 GCOW No 6614 NLY_C No 6615 MDWD No 6616 VLY_A No 6617 TLF No 6618 DSWL No 6619 AXON No 6620 TORM No 6621 ORIG No 6622 AB No 6623 SJT No 6624 CLR No 6625 TISI No 6626 NVLN No 6627 DS_C No 6628 EMITF No 6629 MINDP No 6630 PYT No 6631 DDC No 6632 LBDC No 6633 CBPO No 6634 MTGE No 6635 GS_A No 6636 LEN-B No 6637 NTAP No 6638 PEB_D No 6639 BSX No 6640 KBSF No 6641 GPX No 6642 WWR No 6643 MZOR No 6644 SHE No 6645 OGEN No 6646 BGY No 6647 AMX No 6648 MLP No 6649 LPCN No 6650 DHXM No 6651 JBHT No 6652 UZB No 6653 EXK No 6654 STKS No 6655 OMED No 6656 EDN No 6657 MGU No 6658 PZN No 6659 CFCOU No 6660 CNBKA No 6661 NYMT No 6662 BFZ No 6663 GOOS No 6664 AWF No 6665 LLL No 6666 AFSI No 6667 WRD No 6668 SCE_B No 6669 PNF No 6670 SYPR No 6671 IMKTA No 6672 SPTS No 6673 DCO No 6674 STON No 6675 ISSC No 6676 DTEA No 6677 LSI No 6678 NUROW No 6679 OBAS No 6680 HVBC No 6681 MLQD No 6682 UIVM No 6683 SAGE No 6684 BANC_C No 6685 OME No 6686 GFY No 6687 AAAP No 6688 EGIF No 6689 GSIT No 6690 INN_B-CL Yes 6691 CTL No 6692 RPM No 6693 AET No 6694 CTBB No 6695 WVVIP No 6696 LTRX No 6697 UEPS No 6698 WR No 6699 SOI No 6700 LBIX No 6701 PCTY No 6702 SINA No 6703 PNRG No 6704 MHK No 6705 PGNX No 6706 ANH_C No 6707 ABDC No 6708 CAI No 6709 FNG No 6710 ZFGN No 6711 SAFE No 6712 AGFSW No 6713 TAST No 6714 AVXS No 6715 IFMK No 6716 HCAPZ No 6717 NOAH No 6718 PLX No 6719 CDL No 6720 OAPH No 6721 PSX No 6722 KODK-WS No 6723 RKDA No 6724 GLOW No 6725 ARL No 6726 CVI No 6727 PRPO No 6728 HIVE No 6729 SNA No 6730 MSTR No 6731 OUT No 6732 CCK No 6733 LFC No 6734 ICPT No 6735 RUBI No 6736 WSO-B No 6737 NGG No 6738 NNVC No 6739 PRME No 6740 AMRC No 6741 LRCX No 6742 IVAC No 6743 LGLR Yes 6744 FMN No 6745 SHG No 6746 MTDR No 6747 PSMB No 6748 TWIN No 6749 AEGN No 6750 RST No 6751 SBGL No 6752 ORCL No 6753 GAINN No 6754 RRGB No 6755 LPTX No 6756 BAS No 6757 HLM_ No 6758 NS_A No 6759 MRAM No 6760 DXPE No 6761 HBM-WS No 6762 HK-WS No 6763 PBIB No 6764 DRRX No 6765 REIS No 6766 OFG_D No 6767 SHNY No 6768 RCI No 6769 SMRT No 6770 BABA No 6771 SEP No 6772 FIT No 6773 WNS No 6774 BLBD No 6775 WFIG No 6776 MIE No 6777 EYEG No 6778 BERY No 6779 TNXP No 6780 JSYNW No 6781 BGH No 6782 EEX No 6783 AIV_A No 6784 RMPL_ No 6785 RDY No 6786 PLT No 6787 WFHY No 6788 GMTA No 6789 NS No 6790 MELI No 6791 SYMX No 6792 ELTK No 6793 IO No 6794 USB_A No 6795 NAV No 6796 AYX No 6797 GOOG No 6798 NS_B No 6799 JW-A No 6800 PB No 6801 ALL_B No 6802 PFMT No 6803 XGTI No 6804 FGL No 6805 THRM No 6806 HIFR No 6807 GPL No 6808 MMV No 6809 FOR No 6810 IBMK No 6811 ONS No 6812 CA No 6813 KMI_A No 6814 BRN No 6815 MRCC No 6816 HCM No 6817 CEO No 6818 BOBE No 6819 DHR No 6820 ATHX No 6821 PSB_V No 6822 AAT No 6823 DWAS No 6824 STAR_F No 6825 PNBK No 6826 HDEZ No 6827 LL No 6828 LARK No 6829 CGA No 6830 FOXF No 6831 PSC No 6832 CVGW No 6833 MON No 6834 NYRT No 6835 NATH No 6836 XNCR No 6837 SIGM No 6838 PDVW No 6839 IMTE No 6840 WVFC No 6841 FTXO No 6842 CPAC No 6843 BXP_B No 6844 MAB No 6845 SCE_J No 6846 FLOW No 6847 ZAGG No 6848 BAC-WS-B No 6849 LIFE No 6850 WBK No 6851 CMO_E No 6852 TK No 6853 EDR No 6854 MOXC No 6855 INVH No 6856 IRCP No 6857 VALE No 6858 AMCX No 6859 SLAB No 6860 FSBW No 6861 CFX No 6862 BSTC No 6863 CHSP No 6864 PSEC No 6865 AGN_A No 6866 SHO No 6867 GHS No 6868 WYIGU No 6869 FSS No 6870 VRNT No 6871 FIHD No 6872 MKC-V No 6873 GTXI No 6874 TTF No 6875 LYV No 6876 APU No 6877 KEY_I No 6878 PHK No 6879 NETS No 6880 EFC No 6881 TAXR No 6882 ITW No 6883 TPVY No 6884 CTXRW No 6885 BMTC No 6886 BRFS No 6887 PGTI No 6888 NDRO No 6889 IMI No 6890 VII No 6891 MLR No 6892 TKR No 6893 PMF No 6894 ELY No 6895 PE No 6896 TRV No 6897 INN_C No 6898 FDP No 6899 PFSW No 6900 NTEC No 6901 GBCI No 6902 SVRA No 6903 GSD No 6904 BBY No 6905 CBF No 6906 APLP No 6907 ASRVP No 6908 NKE No 6909 NVEE No 6910 RYB No 6911 KB No 6912 RLGY No 6913 DUC No 6914 WRB No 6915 ANW No 6916 MBT No 6917 TITN No 6918 LMHB No 6919 GBLIL No 6920 SGLBW No 6921 NRCIB No 6922 WHLRD No 6923 ALL_E No 6924 CEF No 6925 NTZ No 6926 OMAA No 6927 PFD No 6928 BNS No 6929 SPXT No 6930 MACQU No 6931 TGP_B No 6932 ICE No 6933 TACT No 6934 MTGEP No 6935 LINC No 6936 BOE No 6937 FULLL No 6938 TYPE No 6939 PKI No 6940 CONE No 6941 ASHX No 6942 REI No 6943 JONE No 6944 MHE No 6945 TAHO No 6946 TDW-WS-B No 6947 GOV No 6948 PMPT No 6949 NAVI No 6950 TRNO No 6951 USAU No 6952 TTC No 6953 PHO No 6954 HL_B No 6955 NVFY No 6956 BYSI No 6957 KBAL No 6958 BSET No 6959 WRLSW No 6960 TLDH No 6961 SLTB No 6962 JHMF No 6963 SIMO No 6964 X No 6965 OHRP No 6966 SDPI No 6967 BERN No 6968 ARW No 6969 NOW No 6970 TPC No 6971 AVID No 6972 AIG No 6973 LUV No 6974 NESR No 6975 FLLV No 6976 AOSL No 6977 ZB_H No 6978 ARR_B No 6979 ZNGA No 6980 CDW No 6981 NEE_G-CL No 6982 BRKS No 6983 SPLK No 6984 PBSM No 6985 VWR No 6986 NID No 6987 BHAC No 6988 MS_A No 6989 RVEN No 6990 TSU No 6991 NLNK No 6992 SMMF No 6993 SIG No 6994 SBLK No 6995 MRCY No 6996 ICBK No 6997 ARA No 6998 ABX No 6999 RDCM No 7000 IDE No 7001 GABC No 7002 SNN No 7003 SCHN No 7004 PSA_V No 7005 HTLF No 7006 BHACR No 7007 YESR No 7008 XPLR No 7009 PNFP No 7010 CBG No 7011 DFEN No 7012 CBS No 7013 SQM No 7014 XFLT No 7015 QTNA No 7016 CIC-WS No 7017 SID No 7018 ARRS No 7019 RY_T No 7020 SC No 7021 VLP No 7022 MIW No 7023 MAG No 7024 CTW No 7025 IQDG No 7026 CHMI No 7027 EZT No 7028 ADES No 7029 CUI No 7030 NOG No 7031 NHC No 7032 CVA No 7033 JD No 7034 ALEX No 7035 ESGR No 7036 ATACR No 7037 APC No 7038 NNY No 7039 ING No 7040 VVC No 7041 WGO No 7042 WVE No 7043 HGSH No 7044 INDUW No 7045 LMOS No 7046 FVC No 7047 GJP No 7048 NCR No 7049 LII No 7050 CETXW No 7051 BANX No 7052 IOR No 7053 PBIP No 7054 ZIONZ No 7055 QUMU No 7056 CIE No 7057 INTX No 7058 IMAX No 7059 FISI No 7060 RDIB No 7061 QIWI No 7062 EYLD No 7063 ARH_C No 7064 GLU_A No 7065 SUMR No 7066 NRZ No 7067 LCA No 7068 HTLD No 7069 IMMU No 7070 CTY No 7071 EVEP No 7072 BCX No 7073 ABEV No 7074 BY No 7075 GGP_A No 7076 WNEB No 7077 SAN_C No 7078 RF No 7079 NNN_E No 7080 ESBA No 7081 VBFC No 7082 PCSB No 7083 MKTX No 7084 CPAH No 7085 SERV No 7086 BLIN No 7087 TRN No 7088 EXPO No 7089 GLDW No 7090 ADHD No 7091 VKTXW No 7092 RHI No 7093 EEI No 7094 LINU No 7095 TIF No 7096 RLI No 7097 BKN No 7098 ALOG No 7099 HHS No 7100 TEAR No 7101 TOO_B No 7102 KAACU No 7103 ACC No 7104 METC No 7105 MAC No 7106 FIV No 7107 SLIM No 7108 OXLCM No 7109 FAT No 7110 MYL No 7111 MFT No 7112 GNE No 7113 STL No 7114 VEEV No 7115 KERX No 7116 SIVB No 7117 NSA No 7118 EPIX No 7119 WMGIZ No 7120 UBIO No 7121 AQB No 7122 TUES No 7123 TEF No 7124 TEN No 7125 XSHQ No 7126 TATT No 7127 USAK No 7128 MGF No 7129 WNRL No 7130 KEYW No 7131 VAR No 7132 FOMX No 7133 ATLC No 7134 HPJ No 7135 ANSS No 7136 AGGY No 7137 EYE No 7138 LMRK No 7139 WIN No 7140 NOVT No 7141 PCF No 7142 TBLU No 7143 YUME No 7144 EVT No 7145 TXRH No 7146 FIVE No 7147 BCBP No 7148 GMED No 7149 GIGA No 7150 UITB No 7151 TCTL No 7152 SMCI No Summary statistics Total observations: 7153 Normal log-returns: 100 Non-normal log-returns: 7053 Normal/Total: 1.4 % Concluding remarks # As seen from the table above, the data doesn\u0026rsquo;t support the claim that stock returns follow a normal distribution, and by extension it does not support the claim that stock prices follow a log-normal process. Yet of the majority of people you interact will assume that is an unquestionable fact and question your sanity and intelligence. Some will even say things like \u0026ldquo;reality is too complex to be modelled\u0026rdquo; (which is true!), but then turn around and act like they didn\u0026rsquo;t just say that and throw at you layers of fancy math and fancier words to justify why the formulas make sense. . .\nand then there\u0026rsquo;s me, just sat in a corner. . .\nIn practice, market makers, and other participants, use proprietary pricing models \u0026ndash; some based on the BS model with a lot of fine-tuning, others based on other pricing theories altogether.\nWhat about other instruments like bonds and commodities? # I\u0026rsquo;ve not had the time to repeat the test for those assets yet, but if you have the data and need someone to implement test for those, pop me an email here or reach out on Linkedin.\nIf you found this analysis interesting feel free to share on socials with any of the buttons below.\n","date":"3 September 2023","externalUrl":null,"permalink":"/research/log_returns_normality/","section":"Research","summary":"","title":"The normality of log-returns in stocks","type":"research"},{"content":"","date":"18 May 2022","externalUrl":null,"permalink":"/coding/","section":"Coding","summary":"","title":"Coding","type":"coding"},{"content":" This is a primer on the analysis of the Commitments of Traders (CoT) report. The goal here is just to showcase how to add this weekly report, into a wider analytical framework of your choice. I\u0026rsquo;ve also provided commented code, so you can reproduce the results locally.\nFor the sake of brevity, I will not expand on what this report covers, the assumption here is that you already have some understanding. For an explanation please refer to any decent source on the web, i.e. Wikipedia, etc.\nIn this post I will focus on the EUR/USD currency pair in 2023 report. There\u0026rsquo;s no particular reason why, it\u0026rsquo;s just a popular pair with lots publicly available of data, both on the spot and futures market.\nA popular way of using the CoT as an indicator, is to take an asset from the futures market and plot it against the spot asset, i.e. EUR/USD futures price from the CoT report will be drawn against the EUR/USD weekly spot. This could help to spot extreme positions in either large speculators or large commercials, and could, depending on the market, signal trend continuation or reversal.\n1. Data # Ticker: EUR/USD\nType:\nSpot market: OHLCV Futures market: Open Interest Timeframe: calendar year 2023\nFrequency: weekly\nFirst point of order is retrieving this report:\n# cot_downloader.py # # Download all available CoT FuturesOnly reports from CFTC website import requests from bs4 import BeautifulSoup from pathlib import Path from zipfile import ZipFile def cot_bulk_downloader(): \u0026#34;\u0026#34;\u0026#34; Downloads all standard Commitment of Traders Futures only reports. :return: 0 if ok | 1 if error -\u0026gt; int \u0026#34;\u0026#34;\u0026#34; url = \u0026#39;https://www.cftc.gov/MarketReports/CommitmentsofTraders/HistoricalCompressed/index.htm\u0026#39; out_path = Path.cwd() / \u0026#39;datasets\u0026#39; / \u0026#39;commitments-of-traders\u0026#39; # avoid re-downloading if the files have already been downloaded if out_path.exists(): return 0 Path.mkdir(out_path, exist_ok=True, parents=True) try: response = requests.get(url) soup = BeautifulSoup(response.text, \u0026#39;html.parser\u0026#39;) for name in soup.findAll(\u0026#39;a\u0026#39;, href=True): file_url = name[\u0026#39;href\u0026#39;] if file_url.endswith(\u0026#39;.zip\u0026#39;): # split based on url \u0026#34;/\u0026#34; path (all files are .zip) and retain \u0026#34;filename.zip\u0026#34; filename = file_url.split(\u0026#39;/\u0026#39;)[-1] if \u0026#39;deacot\u0026#39; in filename: out_name = out_path.joinpath(filename) zip_url = \u0026#39;https://www.cftc.gov/files/dea/history/\u0026#39; + filename # the GET request triggers the download action resp = requests.get(zip_url, stream=True) if resp.status_code == requests.codes.ok: print(f\u0026#39;Downloading {filename} . . .\u0026#39;) with open(out_name, \u0026#39;wb\u0026#39;) as f: for chunk in resp.iter_content(): if chunk: f.write(chunk) f.close() print(\u0026#39;Finished downloading report\u0026#39;) except Exception as error: print(f\u0026#34;Unexpected error: {error}\u0026#34;) return 1 return 0 def bulk_unzipper(target_dir): \u0026#34;\u0026#34;\u0026#34; Unzips all archives within the input directory. :param target_dir: input directory -\u0026gt; Path-like object :return: 0 if ok | 1 if error -\u0026gt; int \u0026#34;\u0026#34;\u0026#34; # if the directory exists and there\u0026#39;s a zip file in it, # then proceed with bulk unzipping try: for file in target_dir.iterdir(): if str(file).endswith(\u0026#39;.zip\u0026#39;): print(f\u0026#39;Unzipping {file} . . .\u0026#39;) with ZipFile(file, \u0026#39;r\u0026#39;) as zip_object: filename = zip_object.filename.split(\u0026#39;/\u0026#39;)[-1] # after split consider only the \u0026#39;deacotXXXX.zip part filename = filename.split(\u0026#39;.zip\u0026#39;)[0] # consider only the \u0026#39;deacotXXXX\u0026#39; string zip_object.extractall(target_dir / filename) except Exception as error: print(f\u0026#34;Unexpected error: {error}\u0026#34;) return 1 return 0 def cot_data_bootstrap(): \u0026#34;\u0026#34;\u0026#34; Seed other modules with data. :return: int -\u0026gt; 0 if ok, 1 if error \u0026#34;\u0026#34;\u0026#34; try: return_val = cot_bulk_downloader() # all is well so proceed to unzip if return_val == 0: # path below is created by bulk downloader so no I/O error cot_dir = Path.cwd() / \u0026#39;datasets\u0026#39; / \u0026#39;commitments-of-traders\u0026#39; bulk_unzipper(cot_dir) except Exception as error: print(f\u0026#39;Unexpected error: {error}\u0026#39;) return 1 return 0 2. The Analysis # Now that the futures data has been downloaded, we can start thinking of what to do with it. Since this is a primer, I will compute relatively easy metrics,\nnet positions of large speculators and commercials (aka hedgers) market sentiment speculators sentiment where,\n\\( net\\ position = long\\ contracts\\ - short\\ contracts \\)\n\\( market\\ sentiment = speculators\\ net\\ position\\ - commercials\\ net\\ position \\)\n\\( speculators\\ sentiment = \\dfrac{speculators\\ long\\ contracts}{total\\ speculators\\ contracts} * 100 \\) (%)\nI made up the last formula, but I find it sensible to have a ratio to quickly gauge if speculators are heavily long/short in relative terms, so if speculator sentiment is for example 35%, then large traders are heavily short. That could be noise or could be something worth looking into \u0026ndash; it depends on how intimate is one\u0026rsquo;s knowledge in any given market.\nThe code for the formulas above is:\n# cot_yearly_analysis.py def net_positions(instrument): \u0026#34;\u0026#34;\u0026#34; Computes the net position for large speculators and hedgers, where, net_position = long contracts - short contracts e.g., speculator net position = speculator long contracts - speculators short contracts. Non-reportable positions are omitted (aka small speculator positions) :param instrument: futures instrument represented as the ticker -\u0026gt; str :return: net positions of speculators and hedgers respectively -\u0026gt; tuple(int) \u0026#34;\u0026#34;\u0026#34; speculators_net_position = instrument[2] - instrument[3] commercials_net_position = instrument[5] - instrument[6] return speculators_net_position, commercials_net_position def market_sentiment(instruments): \u0026#34;\u0026#34;\u0026#34; Compute market sentiment from CoT report, where, market sentiment = speculators net position - commercials net position :param instruments: iterable of instruments represented as tickers -\u0026gt; list :return: delta between net positions of large speculators and commercials -\u0026gt; int \u0026#34;\u0026#34;\u0026#34; non_commercials_net_position, commercials_net_position = net_positions(instruments) return non_commercials_net_position - commercials_net_position def speculators_sentiment(instrument): \u0026#34;\u0026#34;\u0026#34; Compute speculator long and short positions (contracts) from CoT report, where, speculators_long = speculators long / (spec. long + spec. short) speculators_short = speculators short / (spec. long + spec. short) :param instrument: futures instrument represented as the ticker -\u0026gt; str :return: speculators long positions and short positions -\u0026gt; tuple(float) \u0026#34;\u0026#34;\u0026#34; speculators_long = instrument[2] / (instrument[2] + instrument[3]) speculators_short = instrument[3] / (instrument[2] + instrument[3]) return round(speculators_long, 4), round(speculators_short, 4) Now that the formulas are out of the way, we can look at the results in the next section. But first I\u0026rsquo;ll need to show the code used to draw the plot:\n# plotter.py import plotly.graph_objects as go from pathlib import Path from plotly.subplots import make_subplots def generic_time_series(df, x_column_name, y_column_name, **kwargs): \u0026#34;\u0026#34;\u0026#34; Plots a time series. Assumptions when plotting the time series: - X-axis is a Date or DateTimeIndex (sensible for a time series) - Y-axis is a pandas Series :param df: input Dataframe -\u0026gt; pandas Dataframe :param x_column_name: X-axis pandas column name -\u0026gt; str :param y_column_name: Y-axis pandas column name -\u0026gt; str :param kwargs: optional args -\u0026gt; dict :return: Null \u0026#34;\u0026#34;\u0026#34; fig = make_subplots( rows=2, cols=1, shared_xaxes=True, shared_yaxes=False ) # N.B.: when using the graph objects API from Plotly, Line plots are rendered with the # \u0026#34;Scatter\u0026#34; class for some reason. # add main plot/trace fig.add_trace( go.Scatter( x=df.index.values, y=df[y_column_name], mode=\u0026#34;lines\u0026#34;, name=kwargs.get(\u0026#34;y_label\u0026#34;) ), row=1, col=1 ) # there\u0026#39;s one or more to additional plots if \u0026#34;extra_x\u0026#34; or \u0026#34;extra_y_1\u0026#34; or \u0026#34;extra_y_2\u0026#34; in kwargs: # add secondary trace(s), aka actual subplots in Plotly lingo fig.add_trace( go.Scatter( x=df.index.values, y=kwargs.get(\u0026#34;extra_y_1\u0026#34;), # there has to be a y-axis on the secondary plot mode=\u0026#34;lines\u0026#34;, name=kwargs.get(\u0026#34;extra_y_1_legend_label\u0026#34;, \u0026#34;\u0026#34;) ), row=2, col=1 ) fig.add_trace( go.Scatter( x=df.index.values, y=kwargs.get(\u0026#34;extra_y_2\u0026#34;), # there has to be a y-axis on the secondary plot mode=\u0026#34;lines\u0026#34;, name=kwargs.get(\u0026#34;extra_y_2_legend_label\u0026#34;, \u0026#34;\u0026#34;) ), row=2, col=1 ) # update y-axis properties of sub trace(s) y_subplot_label = \u0026#34; \u0026#34;.join(kwargs.get(\u0026#34;extra_y_1_legend_label\u0026#34;).split(\u0026#34; \u0026#34;)[1:]) fig.update_yaxes(title_text=y_subplot_label, row=2, col=1) # Canvas styling fig.update_xaxes(tickangle=45) fig.update_yaxes(title_text=kwargs.get(\u0026#34;y_label\u0026#34;, \u0026#34;Y\u0026#34;), row=1, col=1) fig.update_layout(title_text=kwargs.get(\u0026#34;plot_title\u0026#34;, \u0026#34;No title provided\u0026#34;)) # exist_ok = True makes sure \u0026#34;charts\u0026#34; directory is not created or overwritten if it # already exists Path.cwd().joinpath(\u0026#34;charts\u0026#34;).mkdir(exist_ok=True) filename = f\u0026#34;charts/{kwargs.get(\u0026#39;filename\u0026#39;, \u0026#39;Y\u0026#39;)}\u0026#34; fig.write_image(f\u0026#34;{filename}.svg\u0026#34;) fig.write_html(f\u0026#34;{filename}.html\u0026#34;) 3. Results and concluding remarks # Taken as is, there is no discernible pattern or connection between net positions from the CoT and the spot market for EUR/USD, yet it doesn\u0026rsquo;t mean the report is useless. After all I only looked at a year\u0026rsquo;s worth of data. Additionally, supply \u0026amp; demand levels \u0026ndash; where a report like this would shine \u0026ndash; are nearly impossible to estimate with currencies given central banks liberal money printing practices. For a physical commodity market it should be more useful, given that supply \u0026amp; demand are linked to physical inventories, i.e. a cattle trader cannot print a billion more cows overnight , a central bank can with the domestic currency.\nTo make the most of this report, it\u0026rsquo;s best to collect the measurements across several points in time, because market conditions change, e.g. net positions that seem extreme in current market conditions might not be so extreme if measured against another point in the past. Building an index like the CPI is the best way to maximise the value of the CoT report.\nFinally, the driver code that brings all the code snippets together:\n# driver.py if __name__ == \u0026#39;__main__\u0026#39;: import pandas as pd from cot_downloader import cot_data_bootstrap, futures_dir, Path from yahoo_finance_downloader import prepare_ticker_for_yf_download from cot_analysis import market_sentiment, net_positions, speculators_sentiment from plotter import generic_time_series cot_data_bootstrap() # seed application with data # visually inspect the report .txt to find these column names columns = [ \u0026#39;Market and Exchange Names\u0026#39;, \u0026#39;As of Date in Form YYYY-MM-DD\u0026#39;, \u0026#39;Noncommercial Positions-Long (All)\u0026#39;, \u0026#39;Noncommercial Positions-Short (All)\u0026#39;, \u0026#39;Noncommercial Positions-Spreading (All)\u0026#39;, \u0026#39;Commercial Positions-Long (All)\u0026#39;, \u0026#39;Commercial Positions-Short (All)\u0026#39;, \u0026#39;Nonreportable Positions-Long (All)\u0026#39;, \u0026#39;Nonreportable Positions-Short (All)\u0026#39; ] # in a more dynamic setting, these vars will come from user command line input or # web form, etc. focus_instrument = \u0026#34;EUR/USD\u0026#34; focus_year = \u0026#34;2023\u0026#34; start_date = \u0026#34;2022-12-31\u0026#34; end_date = \u0026#34;2023-12-31\u0026#34; analysis_title = \u0026#34;Weekly Close prices\u0026#34; currency = \u0026#34;USD\u0026#34; frequency = \u0026#34;1wk\u0026#34; futures_data = pd.read_csv( Path.cwd() / futures_dir / f\u0026#34;deacot{focus_year}\u0026#34; / \u0026#39;annual.txt\u0026#39;, delimiter=\u0026#39;,\u0026#39;, usecols=columns ) spot_instrument = prepare_ticker_for_yf_download(focus_instrument) spot_data = yf.Ticker(spot_instrument).history( start=start_date, end=end_date, interval=frequency ) # map spot asset to futures market equivalent. For stocks or similar, they\u0026#39;re # equivalent, but for currencies they are different, e.g \u0026#34;EUR/USD\u0026#34; spot maps to # \u0026#34;EURO FX\u0026#34; in the futures market. spot_to_futures_map = { \u0026#34;EUR/USD\u0026#34;: \u0026#34;EURO FX\u0026#34;, \u0026#34;EURUSD=X\u0026#34;: \u0026#34;EURO FX\u0026#34;, } if spot_instrument in spot_to_futures_map.keys(): futures_instrument = spot_to_futures_map[spot_instrument] else: futures_instrument = focus_instrument speculators = [] hedgers = [] for market in futures_data.values: if futures_instrument in market[0]: market_delta = market_sentiment(market) speculators_net_position, hedgers_net_position = net_positions(market) speculators_long, speculators_short = speculators_sentiment(market) speculators.append( (market[1], speculators_net_position, speculators_long, speculators_short) ) hedgers.append((market[1], hedgers_net_position)) # primary plot with historical spot data x_column_name = spot_data.index.name # _name is a column name of the Dataframe y_column_name = \u0026#34;Close\u0026#34; x_label = \u0026#34;Date\u0026#34; # _label is what is shown on the plot y_label = f\u0026#34;{spot_instrument} {y_column_name} price ({currency})\u0026#34; generic_time_series( spot_data, x_column_name, y_column_name, filename=f\u0026#34;{spot_instrument}_{data_frequency}_{focus_year}\u0026#34;, plot_title=f\u0026#34;{spot_instrument} {analysis_title} ({currency}) {focus_year}\u0026#34;, x_label=x_label, y_label=y_label, # secondary plot(s) data extra_y_1=[net_position[1] for net_position in speculators], extra_y_2=[net_position[1] for net_position in hedgers], extra_y_1_legend_label=\u0026#39;Speculators net position\u0026#39;, extra_y_2_legend_label=\u0026#39;Hedgers net position\u0026#39;, ) What about other commodities or currencies? # I only covered the EUR/USD pair for convenience. If you want me to focus on other instruments, you can email me here or reach out on Linkedin.\nIf you found this analysis interesting feel free to share with any of social media links below.\n","date":"3 September 2021","externalUrl":null,"permalink":"/research/commitments_of_traders_primer_analysis/","section":"Research","summary":"","title":"Commitments of traders primer analysis","type":"research"},{"content":" Me # I\u0026rsquo;m inquisitive by nature and driven by hard challenges and complex problems. Financial markets are among the most intricate systems we interact with, which is what continues to pull me toward them.\nSoftware Engineering is my other enduring interest, so I tend to spend both work and spare-time either writing software or reading quantitative finance material, in the ever elusive search for alpha.\nInterests \u0026amp; hobbies # Activity Yield 🥊 Muay Thai Discipline and humility. 🎾 Tennis Patience, strategy, and continuous improvement. 💪 Fitness Energy and consistency. ✈️ Travel New perspectives and great stories. The website # The name of the website follows from the Hebrew word:\n\u0026ldquo;Livyathan\u0026rdquo; \u0026ldquo;Livyatan\u0026rdquo; \u0026ldquo;Leviathan\u0026rdquo;\nwhich are all synonymous and refer to a giant sea creature. According to Biblical lore and other literatures and cultures, a Leviathan is an entity that embodies:\nimmense, untamed strength a force of nature chaos and danger The kind of force that exists beyond human manipulation and authority. To quote a verse from the Bible:\nHe has no equal on earth — a creature devoid of fear! - Job (41:33)\nI\u0026rsquo;m not the religious type but like to draw inspiration from any source, and find the quote aspirational.\nFor projects visit: Projects\nFor any enquiries visit: Contact\n","date":"3 June 2021","externalUrl":null,"permalink":"/about/","section":"Home","summary":"","title":"About","type":"page"},{"content":"","date":"3 June 2021","externalUrl":null,"permalink":"/tags/about-us/","section":"Tags","summary":"","title":"About Us","type":"tags"},{"content":"","date":"3 June 2021","externalUrl":null,"permalink":"/tags/home/","section":"Tags","summary":"","title":"Home","type":"tags"},{"content":"","date":"3 June 2021","externalUrl":null,"permalink":"/tags/introduction/","section":"Tags","summary":"","title":"Introduction","type":"tags"},{"content":"","date":"3 June 2021","externalUrl":null,"permalink":"/tags/landing-page/","section":"Tags","summary":"","title":"Landing Page","type":"tags"},{"content":"","date":"3 June 2021","externalUrl":null,"permalink":"/tags/presentation/","section":"Tags","summary":"","title":"Presentation","type":"tags"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":" 2 Project(s) 1 App(s) Selected Projects Retroedge A Rust-based trading simulator Betting Exchange A Rust \u0026amp; Python event-driven betting exchange prototype ","externalUrl":null,"permalink":"/","section":"Home","summary":"","title":"Home","type":"page"}]