<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[HangukQuant Research]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com</link><image><url>https://substackcdn.com/image/fetch/$s_!LX9y!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png</url><title>HangukQuant Research</title><link>https://www.research.hangukquant.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 17 Aug 2026 19:42:44 GMT</lastBuildDate><atom:link href="https://www.research.hangukquant.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[QUANTA GLOBAL PTE. LTD. 202328387H.]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[hangukquant@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[hangukquant@substack.com]]></itunes:email><itunes:name><![CDATA[HangukQuant]]></itunes:name></itunes:owner><itunes:author><![CDATA[HangukQuant]]></itunes:author><googleplay:owner><![CDATA[hangukquant@substack.com]]></googleplay:owner><googleplay:email><![CDATA[hangukquant@substack.com]]></googleplay:email><googleplay:author><![CDATA[HangukQuant]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Quantitative Trading - Diagnosing a Live-HFT Strategy]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-diagnosing-a</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-diagnosing-a</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Mon, 17 Aug 2026 17:36:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!b96A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392325a5-2e6a-40d4-a101-750926b9bd0b_2540x1640.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Now this one&#8217;s gonna be a pretty interesting (and important) post, so take a cuppa and let&#8217;s get to it.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-diagnosing-a">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[HFT MM: Detailed Guide to Queue Modelling and Calibration]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com/p/hft-mm-detailed-guide-to-queue-modelling</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/hft-mm-detailed-guide-to-queue-modelling</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 14 Aug 2026 15:54:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AL7a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VJtY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VJtY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 424w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 848w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 1272w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VJtY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:203352,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/211191137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VJtY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 424w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 848w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 1272w, https://substackcdn.com/image/fetch/$s_!VJtY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a35b9f7-850e-4a90-8fc7-fb75e184cde5_1610x920.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Note that <a href="https://quantpylib.hangukquant.com/pricing/pricing/">terminal access pass</a> cost increases in 3 days.</strong></p><h2>Queue Modelling in HFT Simulations</h2><p>In HFT market making, running high-fidelity tick-data simulations is particularly challenging. It is easy to invent false artefacts around market microstructure which generate positive PnL but do not hold in practice. This is because we make assumptions around important considerations like latency, queue priority, market impact and so on.</p><p>At a high level, an execution simulation has to be concerned with:</p><ol><li><p>When our order lands on the order book.</p></li><li><p>When our cancellation lands on the order book.</p></li><li><p><strong>Our estimated queue position relative to exogenous market actions.</strong></p></li><li><p>The impact of other traders reacting to our orders.</p></li><li><p><strong>The endogenous impact of our orders on the simulated order book.</strong></p></li></ol><p>The first two are latency problems. Order-latency distributions may be backed out from our own order traces, with an appropriate sampling method. Similarly, an order remains live while its cancellation is in flight. Market events between these timestamps have to be applied against the correct exchange-side state.</p><p>The third is the usual queue-position problem: how much liquidity is ahead of us, and how does that quantity change as trades, submissions, modifications and cancellations occur?</p><p>The fourth is a much harder problem. Historical replay tells us how other participants behaved in the observed market. It does not tell us how they would have behaved had our simulated order been larger, smaller or absent. Modelling this properly requires an endogenous model of external order flow - we will leave that outside the scope of this post.</p><p>Our focus in this post is the theoretical basis of points 3 and 5. In particular, we will separate two ideas which are often mixed together under &#8220;queue modelling&#8221;:</p><ul><li><p><strong>Impact modelling:</strong> how should our order change the displayed and matchable liquidity inside the replay?</p></li><li><p><strong>Position modelling:</strong> where should our order sit, and how should exogenous events change the quantity ahead of it?</p></li></ul><p><strong>Given different choices to queue models, we also want to know how we may tune or calibrate them from a statistical framework.</strong></p><h3>MBO vs MBP</h3><p>When we have market-by-order data&#8212;MBO (L3)&#8212;queue reconstruction is relatively straightforward. The feed identifies individual order submissions, modifications and cancellations. Assuming price-time priority, we can reconstruct the orders at a level and insert our own order according to its exchange-arrival timestamp.</p><p>When an external order is cancelled, we know which order left the queue. We therefore know whether the cancellation occurred ahead of or behind us.</p><p>In crypto, we typically have market-by-price data&#8212;MBP (L2). <strong>The feed gives us aggregate quantity at each price but does not identify the orders making up that quantity.</strong></p><p>Consider a level displaying ten units. The level later falls to six. We know that four units have left, but the L2 update does not tell us where those units were in the queue. </p><p>If they were ahead of our order, our position has improved by four. If they were behind us, our position has not improved at all. <strong>This is the crux of estimating queue priority and building queue models.</strong></p><p>An optimistic model may remove it from ahead of us; a pessimistic model may remove it from behind us; a probabilistic model sits somewhere between the two.</p><p><strong>Before we get to this position problem, there is a lesser asked but equally important question.</strong></p><p>Suppose the historical L2 book displays ten units at a price and we submit a two-unit order. Should the simulated book now display twelve units, or should our two units be treated as part of the ten already observed?</p><p>There is no one-size-fits-all answer. It depends on our order size, the liquidity of the market and, importantly, whether we were already quoting on the book used to record the historical data. This is an orthogonal question to point 4&#8212;should our orders should be represented inside the public book?</p><p><strong>The good news is that we can answer such difficult questions by tuning our queue models and parameters and comparing them against empirical results, thereby reducing the dimensions of our problem.</strong> </p><p>In QuantPylib, the L2 and L3 order books are mapped through a common data structure. QuantPylib&#8217;s replay logic implements the discussed policies.</p><p><strong>We will discuss how synthetic L2 MBP data can be projected onto an L3 MBO book by separating liquidity into anonymous and private sizes, over which we may configure different queueing and impact policies.</strong></p><h2>Projecting L2 into an L3 State</h2><p>Consider a single price level displaying ten units of liquidity. Our two-unit order lands at the same price.</p><p>There are two ways to project the new state.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jVCi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jVCi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 424w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 848w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 1272w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jVCi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png" width="578" height="317.18543956043953" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:799,&quot;width&quot;:1456,&quot;resizeWidth&quot;:578,&quot;bytes&quot;:1168380,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/211191137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jVCi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 424w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 848w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 1272w, https://substackcdn.com/image/fetch/$s_!jVCi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a6aa226-a3c8-4631-a240-777f878918db_1693x929.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Additive Impact</h3><p>The additive model is simple. Historical public liquidity and our private liquidity are disjoint.</p><p>If the observed L2 quantity is <em>L</em> and our total private quantity is <em>O</em>, the matchable size is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;T=L+O&quot;,&quot;id&quot;:&quot;KIYRPYYLUT&quot;}" data-component-name="LatexBlockToDOM"></div><p>Our order is appended to the price level when it arrives. Subsequent L2 updates change the public quantity independently of our order. Cancelling our order removes its entire remaining size.</p><h3>Borrowed Impact</h3><p>The borrowed model is more challenging because public and private liquidity are no longer disjoint accounting buckets.</p><p>For one side and price, define:</p><ul><li><p><em>L</em>: public size reported by the historical L2 feed;</p></li><li><p><em>O</em>: total size of our active private orders;</p></li><li><p><em>B</em>: private size borrowed from&#8212;and therefore already counted in&#8212;the historical public size;</p></li><li><p><em>E</em>: anonymous external liquidity represented in the synthetic L3 book;</p></li><li><p><em>T</em>: total physical quantity available to the matcher.</p></li></ul><p>The following invariants must hold:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E=L-B&quot;,&quot;id&quot;:&quot;PBXWOMKKXO&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;T=E+O=L+O-B&quot;,&quot;id&quot;:&quot;YGMFHEFEHX&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0\\leq B\\leq\\min(L,O)&quot;,&quot;id&quot;:&quot;IMMBFPMTYJ&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>For a fully borrowed-impact model, we target:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;B=\\min(L,O)&quot;,&quot;id&quot;:&quot;FNCQCVCUFH&quot;}" data-component-name="LatexBlockToDOM"></div><p>and therefore:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;T=\\max(L,O)&quot;,&quot;id&quot;:&quot;MZCIXZEJAH&quot;}" data-component-name="LatexBlockToDOM"></div><p><br>Probably confusing, so let&#8217;s walk through some interesting cases.</p><h3>Private size exceeds the observed level</h3><p>Suppose the historical level displays three units and we submit an order for five:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;L=3,\\qquad O=5&quot;,&quot;id&quot;:&quot;BPOABJAZLN&quot;}" data-component-name="LatexBlockToDOM"></div><p>The private order can borrow only the three units available in the public observation:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;B=3,\\qquad E=0,\\qquad T=5&quot;,&quot;id&quot;:&quot;UFKQCTLHKQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>All three public units are represented by our order. The remaining two units are necessarily additive.</p><p>The cancellation behaviour is slightly less obvious. If we cancel the five-unit order, only its two additive units should disappear from the physical book. The three borrowed units still belong to the historical public observation and must return as anonymous liquidity:</p><pre><code><code>before cancellation:
[ours: 5]

L = 3, O = 5, B = 3, E = 0, T = 5

after cancellation:
[anonymous: 3]

L = 3, O = 0, B = 0, E = 3, T = 3</code></code></pre><p>Cancelling the private claim does not cancel the historical market.</p><h3>Public size moves through private size</h3><p>Now suppose our private order has size ten while the historical L2 level displays five:</p><pre><code><code>L = 5, O = 10, B = 5, E = 0, T = 10</code></code></pre><p>The public level then rises from five to eight:</p><pre><code><code>L = 8, O = 10, B = 8, E = 0, T = 10</code></code></pre><p>The physical matchable size does not change. Three more units of our private order simply become borrowed from the updated public observation.</p><p>If the L2 level subsequently rises to twelve:</p><pre><code><code>L = 12, O = 10, B = 10, E = 2, T = 12</code></code></pre><p>Our full ten-unit order is now borrowed, while the remaining two public units must be represented as anonymous liquidity that queues behind our owned orders.</p><p>The reverse case - suppose the public level falls from twelve to seven:</p><pre><code><code>before:
L = 12, O = 10, B = 10, E = 2, T = 12

after:
L = 7, O = 10, B = 7, E = 0, T = 10</code></code></pre><p>The private order remains physically matchable for ten units. The two anonymous units disappear, while three units of the private order lose their borrowed attribution and become additive.</p><p><strong>The different impact models fundamentally discuss the philosophy of whether our simulated orders should be treated as additional liquidity, or as liquidity already represented in the observed market data.</strong></p><h2>Queue Position Policies</h2><p>Once the impact policy has produced a synthetic L3 level, the queue policy determines how exogenous reductions change our position.</p><p>New public liquidity joins the tail. Historical trades consume liquidity from the head. <strong>The ambiguous event is an L2 size reduction: did the disappearing liquidity sit ahead of us or behind us?</strong></p><h3>Optimistic and pessimistic bounds</h3><p>Consider a borrowed-impact book with ten public units. We submit an order for two:</p><pre><code><code>[anonymous: 8] [ours: 2]</code></code></pre><p>The public level then rises from ten to fifteen. The new liquidity joins the tail:</p><pre><code><code>[anonymous: 8] [ours: 2] [anonymous: 5]</code></code></pre><p>The level subsequently falls back to ten.</p><p>An optimistic, front-cancellation policy removes the five units from the head:</p><pre><code><code>[anonymous: 3] [ours: 2] [anonymous: 5]</code></code></pre><p>Our queue position has improved by five. A subsequent trade for five units consumes the three anonymous units ahead of us and fills our two-unit order.</p><p>A pessimistic, back-cancellation policy removes the five units from the tail:</p><pre><code><code>[anonymous: 8] [ours: 2]</code></code></pre><p>Our position has not improved. The same five-unit trade does not reach us.</p><p><strong>The market data is identical in both cases. Only the queue policy changes.</strong></p><h3>Probabilistic queue models</h3><p>The optimistic and pessimistic models are useful bounds. A probabilistic model allocates the reduction between liquidity ahead of and behind our order.</p><p>Let:</p><ul><li><p><em>A</em>: anonymous quantity ahead of our order;</p></li><li><p><em>H</em>: anonymous quantity behind our order;</p></li><li><p><em>C</em>: observed L2 reduction.</p></li></ul><p>Define the relative queue position:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;x=\\frac{A}{A+H}&quot;,&quot;id&quot;:&quot;GQBRTDKNYN&quot;}" data-component-name="LatexBlockToDOM"></div><p>A simple probability function is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\text{ahead}}(x)\n=\n\\frac{f(x)}\n{f(x)+f(1-x)}&quot;,&quot;id&quot;:&quot;ONDWMFDQKY&quot;}" data-component-name="LatexBlockToDOM"></div><p>where:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f(x)=x^\\gamma&quot;,&quot;id&quot;:&quot;NMUGDXCWQA&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The exponent <em>&#947; &gt; 0</em> controls the curvature of the cancellation-probability function.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AL7a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AL7a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 424w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 848w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 1272w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AL7a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png" width="576" height="343.38461538461536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:868,&quot;width&quot;:1456,&quot;resizeWidth&quot;:576,&quot;bytes&quot;:168201,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/211191137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AL7a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 424w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 848w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 1272w, https://substackcdn.com/image/fetch/$s_!AL7a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5d24a7-67e9-4359-9f33-6c99f29172e0_1601x954.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>All curves meet at <em>x=0.5</em>. When the anonymous quantity is split equally ahead of and behind our order, the model assigns equal cancellation probability to both sides regardless of <em>&#947;</em>.</p><p>For <em>&#947; &gt; 1</em>, the curve becomes steeper around the midpoint. <strong>The model increasingly assigns the reduction to whichever side contains more liquidity</strong>. </p><p>For <em>0 &lt;&#947; &lt; 1</em>, the curve flattens. <strong>Cancellation probabilities are pulled towards </strong><em><strong>0.5</strong></em><strong>, making the model less sensitive to the relative amount of liquidity ahead and behind us.</strong></p><p>In practice, the probability function depends on rather predictable factors such as distance from the top of book. We can generalize the probability function by fitting different curves across reasonable market variables.</p><p>These policy choices and parameters can then be calibrated against empirical  order traces.</p><h2>Calibrating Queue Policies and Parameters</h2><p>We now have several defensible impact and queue models. The remaining question is which model best represents the market we are trying to simulate.</p><p><strong>Calibrating directly against strategy PnL is problematic.</strong> Market-making strategies are state-dependent: one different fill changes inventory, which changes subsequent quotes, cancellations and order sizes. </p><p>The action paths quickly diverge, leaving us unable to determine whether a PnL difference came from the queue model or from the strategy.</p><p>Instead, we calibrate through a <strong>closed-action replay</strong>. <strong>We hold the live order actions fixed and allow only their simulated outcomes to change.</strong></p><h3>Trace and tick-data objects</h3><p>Event journalling architecture in quantpylib was discussed here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;2a0ba831-ff8a-43d7-8ac5-90b09fa97beb&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;HFT - Event Journaling and Quantpylib's Native Journaling Architecture&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-28T16:50:41.350Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!m2hC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/hft-event-journaling-and-quantpylibs&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:208855749,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:7,&quot;comment_count&quot;:1,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Consider an order trace containing:</p><ul><li><p>order and cancellation intents;</p></li><li><p>submission and cancellation timestamps;</p></li><li><p>side, price, size, order type and time-in-force;</p></li><li><p>acknowledgements and terminal order states;</p></li><li><p>fills, including their quantity, price and exchange timestamp.</p></li></ul><p>From this trace, we may extract the exogenous action tape:</p><pre><code><code>submit order A at t1
submit order B at t2
cancel order A at t3
submit order C at t4
...</code></code></pre><p>The second object is the public tick-data stream. It contains the market events required to reconstruct exchange-side state:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;4a687eff-3ee1-4e62-807d-bc230107b288&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Designing Institutional Data Capture for Quantitative Research.&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-03T13:17:11.190Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!IRvk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/designing-institutional-data-capture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:204803981,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:9,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><ul><li><p>L2 snapshots and updates;</p></li><li><p>trades;</p></li><li><p>exchange and receive timestamps;</p></li><li><p>&#8230;<br></p></li></ul><p>The market data capture infrastructure in QuantPylib supports these artefacts.</p><p><strong>For a candidate model </strong><em><strong>&#952;</strong></em><strong>, we replay the same action tape of order submissions and cancellations against the same tick-data stream.</strong></p><p><strong>In QuantPylib, the wall clock is swapped against the replay clock and the same trace architecture generates replay trace files.</strong> <strong>We can then compare the live trace fill against the simulated trace file in a queue replay harness.</strong></p><p>We can therefore compare outcomes order by order and determine quantitatively the &#8220;fitness function of a queue model&#8221;.</p><h3>Fill classification</h3><p>Let <em>I</em> be the set of submitted order intents. Define:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;F=\\{i\\in I:q_i>0\\}&quot;,&quot;id&quot;:&quot;RBNTLSHLIV&quot;}" data-component-name="LatexBlockToDOM"></div><p>as the set of orders which received at least one live fill, and:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat{F}_\\theta\n=\n\\{i\\in I:\\widehat{q}_{i,\\theta}>0\\}&quot;,&quot;id&quot;:&quot;RVAMVPUUCS&quot;}" data-component-name="LatexBlockToDOM"></div><p>as the set filled under candidate model <em>&#952;</em>.</p><p><strong>Fill precision is:</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P_\\theta\n=\n\\frac{|F\\cap\\widehat{F}_\\theta|}\n{|\\widehat{F}_\\theta|}&quot;,&quot;id&quot;:&quot;CNQHKELWAX&quot;}" data-component-name="LatexBlockToDOM"></div><p>This answers: when the simulation produces a fill, how often did that order also fill live?</p><p><strong>Fill recall is:</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;R_\\theta\n=\n\\frac{|F\\cap\\widehat{F}_\\theta|}\n{|F|}&quot;,&quot;id&quot;:&quot;ZSJECNDJZJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>This answers: how many live-filled orders did the simulation reproduce?</p><p>A combined F1 score is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;F_{1,\\theta}\n=\n\\frac{2P_\\theta R_\\theta}\n{P_\\theta+R_\\theta}&quot;,&quot;id&quot;:&quot;UHEACQKTGC&quot;}" data-component-name="LatexBlockToDOM"></div><p>A pessimistic model may have excellent precision while missing many live fills. An optimistic model may reproduce most live fills while inventing many others.</p><h3>Lifecycle accuracy</h3><p>Let <em>s<sub>i</sub></em> and <em>s&#770;<sub>i,&#952;</sub></em> be the terminal live and simulated states of order <em>i</em>, such as filled, partially filled, cancelled or rejected.</p><p>Lifecycle accuracy is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A_{\\text{status},\\theta}\n=\n\\frac{1}{|I|}\n\\sum_{i\\in I}\n\\mathbf{1}\n\\left[\ns_i=\\widehat{s}_{i,\\theta}\n\\right]&quot;,&quot;id&quot;:&quot;HETSHOGOFW&quot;}" data-component-name="LatexBlockToDOM"></div><p>This catches differences which a binary filled/unfilled label misses, particularly partial fills and cancellation outcomes.</p><h3>Fill timing</h3><p>For orders filled in both traces, let <em>t<sub>i</sub></em> and <em>t&#770;<sub>i,&#952;</sub></em> be the timestamps of the first live and simulated fills. Define:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_\\theta=F\\cap\\widehat{F}_\\theta&quot;,&quot;id&quot;:&quot;AENGUBQXYZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>A smooth timing score is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_{t,\\theta}\n=\n\\frac{1}{|C_\\theta|}\n\\sum_{i\\in C_\\theta}\n\\exp\n\\left(\n-\\frac{\n|t_i-\\widehat{t}_{i,\\theta}|\n}{\\tau}\n\\right)&quot;,&quot;id&quot;:&quot;INGQITFPUN&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The scale <em>&#964;</em> determines the timing tolerance.  The score ranges from zero to one. A score of one represents identical first-fill timestamps, while values near zero indicate timing errors which are large relative to <em>&#964;</em>. <strong>Semantically, it quantifies how closely the simulated trace reproduces first-fill timing for orders filled in both traces.</strong></p><h3>Fill-price similarity</h3><p>Let <em>p<sub>i</sub></em> and <em>p&#770;<sub>i,&#952;</sub></em> be the live and simulated volume-weighted fill prices for an order filled in both traces.</p><p>The price error in basis points is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e_{i,\\theta}\n=\n10^4\n\\frac{\n|p_i-\\widehat{p}_{i,\\theta}|\n}{p_i}&quot;,&quot;id&quot;:&quot;MTLYKWQJUP&quot;}" data-component-name="LatexBlockToDOM"></div><p>We can convert this into a bounded score:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S_{p,\\theta}\n=\n\\frac{\n\\sum_{i\\in C_\\theta}\nw_i\n\\exp\n\\left(\n-\\frac{e_{i,\\theta}}{\\kappa}\n\\right)\n}{\n\\sum_{i\\in C_\\theta}w_i\n}&quot;,&quot;id&quot;:&quot;GGSIOHHTWH&quot;}" data-component-name="LatexBlockToDOM"></div><p>where <em>&#954;</em> controls the price-error tolerance and:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_i\n=\n\\min(q_i,\\widehat{q}_{i,\\theta})p_i&quot;,&quot;id&quot;:&quot;MYOYMSWJUE&quot;}" data-component-name="LatexBlockToDOM"></div><p>weights the comparison by overlapping filled notional.</p><p>For passive single-price orders, this metric may carry little information: both traces often fill at the submitted limit price. It is more useful for aggressive orders, multi-level executions and partial fills across prices.</p><h3>Cancellation races</h3><p>Cancellation behaviour deserves its own comparison. Let:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_i\n=\n\\mathbf{1}\n\\left[\nt_i^{\\text{cancel intent}}\n<\nt_i^{\\text{fill}}\n<\nt_i^{\\text{cancel effective}}\n\\right]&quot;,&quot;id&quot;:&quot;ZQMJAXTGYZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>indicate that order <em>i</em> filled while its cancellation was in flight. Define <em>r&#770;<sub>i,&#952;</sub></em> similarly for the simulation. Cancellation-race accuracy is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A_{\\text{cancel},\\theta}\n=\n\\frac{1}{|I_{\\text{cancel}}|}\n\\sum_{i\\in I_{\\text{cancel}}}\n\\mathbf{1}\n\\left[\nr_i=\\widehat{r}_{i,\\theta}\n\\right]&quot;,&quot;id&quot;:&quot;NXRMKRQMMF&quot;}" data-component-name="LatexBlockToDOM"></div><p>This exposes a common source of optimistic replay: allowing the order to disappear when the strategy decides to cancel rather than when the cancellation reaches the exchange.</p><h3>Trace similarity as a fitness function</h3><p>The component metrics can be combined into a trace-similarity score:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S(\\theta)\n=\nw_fF_{1,\\theta}\n+\nw_sA_{\\text{status},\\theta}\n+\nw_qS_{q,\\theta}\n+\nw_tS_{t,\\theta}\n+\nw_pS_{p,\\theta}\n+\nw_cA_{\\text{cancel},\\theta}&quot;,&quot;id&quot;:&quot;LUKXMURUXM&quot;}" data-component-name="LatexBlockToDOM"></div><p>with:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sum_j w_j=1&quot;,&quot;id&quot;:&quot;FITZNRAFRM&quot;}" data-component-name="LatexBlockToDOM"></div><p><strong>The weights should reflect the use case.</strong> </p><p>For calibration sessions <em>D<sub>train</sub></em>, we select:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\theta^\\star\n=\n\\arg\\max_{\\theta}\n\\frac{1}{|\\mathcal{D}_{\\text{train}}|}\n\\sum_{d\\in\\mathcal{D}_{\\text{train}}}\nS_d(\\theta)&quot;,&quot;id&quot;:&quot;WWZKTAATIE&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The purpose is not to find the queue model which produces the highest backtest PnL. It is to find the model whose order-level outcomes most closely resemble the empirical trace.</p><p></p><p>thanks for reading. cheers!</p>]]></content:encoded></item><item><title><![CDATA[Tick Data Session Replay in QuantTerminal]]></title><link>https://www.research.hangukquant.com/p/tick-data-session-replay-in-quantterminal</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/tick-data-session-replay-in-quantterminal</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Mon, 10 Aug 2026 15:02:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/bMA0C_WnOSw" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A couple of weeks ago, we introduced the QuantTerminal, equipped with multi-exchange live tick data views.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;4040a6cb-c491-4a52-a6f5-2271313c73d2&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Introduce, the QuantTerminal&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-26T16:26:27.442Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Mrz_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/introduce-the-quantterminal&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:208298022,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:9,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>We also discussed <strong>how can you natively manage your own tick data lake with Quantpylib:</strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;4d400e6e-7183-4d6e-a1b1-9f6dac24aadb&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Manage Your Quantitative Tick Data Lake with Quantpylib&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-08T18:13:40.870Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!EsF3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/manage-your-quantitative-tick-data&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:206133789,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:6,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><br>This is the architecture that supports exchange replay fidelity - from when the exchange processed data, to when it dispatched <strong>(TX)</strong> it, <strong>to when you received (RX) it</strong>, giving you critical observability into your own trading stack&#8217;s processing back-pressure and latency figures.<br><br>There is no substitute for high grade fidelity replay for latency-sensitive analytics involved in quantitative trading - public data simply does not make the cut.<br><br><strong>Today, we release the ability to perform session-replay on your own tick data lake in the QuantTerminal.</strong></p><div id="youtube2-bMA0C_WnOSw" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;bMA0C_WnOSw&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/bMA0C_WnOSw?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Obtain your access pass <strong><a href="https://quantpylib.hangukquant.com/pricing/pricing/">here</a></strong>.<br><br><strong>Terminal access pass cost increases in 1 week. </strong>More on the terminal<strong> <a href="https://quantpylib.hangukquant.com/terminal/">here</a>.<br></strong>Next release will have</p><ul><li><p><strong>private orders, positions, fills display on live exchanges</strong></p></li><li><p><strong>private orders, positions, fills replay on tick data <a href="https://www.research.hangukquant.com/p/hft-event-journaling-and-quantpylibs">with your own trace files.</a></strong></p></li></ul><p>Next post on the blog discusses the architecture and technical details to designing a high fidelity tick data backtest - soon to be released on quantpylib!<br></p>]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 5: hft mm)]]></title><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-fd5</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-fd5</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Thu, 06 Aug 2026 12:40:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Lvvp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi folks, in the last post, we talked about managing an fx basket:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a9e4fa4e-68fb-4a53-9b0e-2f89a6dc5888&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 4: managing an FX basket)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-08-02T13:08:01.259Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!4P_x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-e4c&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:209479046,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:12,&quot;comment_count&quot;:2,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><br>The last of the Quantitative Trading Strategy series pertains to hft mm. Of course, for obvious reasons - I am unwilling to share in detail the specifics. However, I do want to share <strong>a piece of market microstructural analyses between binance and polymarket crypto markets I did. </strong></p><p>This article is abit of a special format - instead of written form, this is simply a <strong>snippet from Lecture 7 of my (yet to be released) hft lectures I have on the topic. Then some food for thought and tricks.</strong></p><p>The specific figures there are no longer applicable due to the changing dynamics of the markets involved, but the techniques therein are applicable no matter and to orthogonal markets&#8230;</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-fd5">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 4: managing an FX basket)]]></title><description><![CDATA[macroeconomic policy, to statistical modelling and portfolio construction]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-e4c</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-e4c</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Sun, 02 Aug 2026 13:08:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4P_x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi folks, we previously modelled this before, but there <strong>have been significant improvements to the modelling and construction accuracies.</strong> We will discuss FX trading today.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4P_x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4P_x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 424w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 848w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 1272w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4P_x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png" width="1456" height="431" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:431,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:744244,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/209479046?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4P_x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 424w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 848w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 1272w, https://substackcdn.com/image/fetch/$s_!4P_x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5967bb21-b651-40ca-90fd-f5643aeea331_3186x944.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br>Currency desks are commonly divided by geography and market structure: G10, EMFX, LatAm, and so on. In FX, the policy regime plays a significant role in price discovery, and central bank leaning is one of the primary sources of price discovery.</p><p><strong>Python Code for replication is provided at the end of the article. </strong></p><p>In this series, we will be looking at trading SGD crosses. The MAS manages the Singapore dollar against a basket of currencies through the S$NEER.</p><p>The regime is normally described as <strong>basket, band and crawl</strong>:</p><ul><li><p><strong>Basket:</strong> SGD is managed against the currencies of Singapore&#8217;s major trading partners rather than against one bilateral rate.</p></li><li><p><strong>Band:</strong> the trade-weighted index is allowed to move within an undisclosed policy band.</p></li><li><p><strong>Crawl:</strong> the slope of that band is reviewed and adjusted as the inflation and growth outlook changes.</p></li></ul><p>These parameters <strong>are not disclosed</strong>, except for rough &#8220;policy guidance&#8221;. MAS may intervene through spot or forward FX transactions. Insofar as possible, market forces are otherwise allowed to determine where the currency trades inside the band.</p><p>I will leave the economic motivation of these policies as self-reading.</p><p>As you may imagine - for a number of business functions (such as fx hedging, speculation) in banks, hedge funds and whatnot - currency desks are undeterred in modelling these parameters.</p><p>We will perform such an exercise with public data and construct a trading strategy on a basket of tradable assets. Since MAS explains policy decisions in qualitative language, we will come up with a simple, algorithmic state machine. </p><p>In order to assess the quality of our policy recalibration, we will cross-reference with United Overseas Bank (UOB)&#8217;s <a href="https://www.uobgroup.com/web-resources/uobgroup/pdf/research/MN_190321.pdf">2019</a> and <a href="https://www.uob.com.sg/web-resources/uobgroup/pdf/research/MN_210415B.pdf">2021</a> paper.</p><p>We will take a look at these subtasks:</p><ul><li><p>data preparation for statistical modelling</p></li><li><p>performing numerical analysis through constrained regression</p></li><li><p>algorithmic reconstruction of policy mid, band and width</p></li><li><p>portfolio construction from proxy index</p></li><li><p>portfolio construction on tradable basket</p></li></ul><h2>data preparation for statistical modelling</h2><p>We require two datasets for the initial statistical model: the official S$NEER history and bilateral SGD exchange rates. Both are available for free from MAS.</p><p>The official S$NEER history can be downloaded as an XLSX file from the <a href="https://www.mas.gov.sg/statistics/exchange-rates/s$neer">MAS exchange-rate statistics page</a>. For our purposes the workbook contains two relevant fields:</p><pre><code><code>date          sneer
1999-01-08    100.00
1999-01-15     99.75
1999-01-22    100.10</code></code></pre><p>Each value represents the <strong>weekly average S$NEER for the week ending on the stated date</strong>. This gives us the dependent variable. We next need a set of explanatory FX rates.</p><h3>daily FX data</h3><p>Daily end-of-period exchange rates are available through the <a href="https://eservices.mas.gov.sg/apimg-portal/api-catalog">MAS API catalogue</a>. The request requires a (free to obtain) API key and returns JSON records. We retain the following currency fields:</p><pre><code><code>USD, CNY, EUR, MYR, JPY, AUD, GBP, IDR,
KRW, THB, CHF, TWD, INR, PHP, VND and CAD</code></code></pre><p>This is our candidate universe, not a claim about the actual basket. The statistical model will determine which currencies receive weight. The raw columns use the following quote convention:</p><pre><code><code>usd_sgd         SGD per 1 USD
eur_sgd         SGD per 1 EUR
jpy_sgd_100     SGD per 100 JPY
idr_sgd_100     SGD per 100 IDR</code></code></pre><p>We normalise this to sgd_xxx convention.</p><p>A complete cross-section is available beginning January 2008. The FX data is daily while the official S$NEER series is weekly. Since the target represents a weekly average, we take the arithmetic average of each FX series over the same week.</p><p>If <em>W<sub>t</sub></em> is the set of daily observations belonging to week <em>t</em>, the weekly normalized FX level is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;F_{t,i}\n=\n\\frac{1}{|W_t|}\n\\sum_{d\\in W_t}P_{d,i}.&quot;,&quot;id&quot;:&quot;VFWABUDFUA&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let <em>S<sub>t</sub></em> denote the official weekly-average S$NEER level for week <em>t</em>. The resulting DataFrame has one row for each common observation week <em>t=0,&#8230;,T</em>. We denote this weekly level panel by</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal D\n=\n\\left[\n\\begin{array}{cccc|c}\nF_{0,1} &amp; F_{0,2} &amp; \\cdots &amp; F_{0,n} &amp; S_0\\\\\nF_{1,1} &amp; F_{1,2} &amp; \\cdots &amp; F_{1,n} &amp; S_1\\\\\n\\vdots &amp; \\vdots &amp; \\ddots &amp; \\vdots &amp; \\vdots\\\\\nF_{T,1} &amp; F_{T,2} &amp; \\cdots &amp; F_{T,n} &amp; S_T\n\\end{array}\n\\right]\n=\n\\left[\\mathbf F\\mid\\mathbf S\\right]\n\\in\n\\mathbb R_{+}^{(T+1)\\times(n+1)}.&quot;,&quot;id&quot;:&quot;VMJVNOVOYV&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The first <em>n</em> columns, <em><strong>F</strong></em>, contain the normalized weekly-average FX levels. The final column, <em><strong>S</strong></em>, contains the corresponding official weekly-average S$NEER levels. In pandas, <code>regression_df</code> is simply the tabular representation of <em>&#119967;</em>.</p><h2>constructing the basket through restricted least squares</h2><p>The statistical problem is to infer a dynamic set of currency weights from the weekly level panel <em>&#119967;=[<strong>F</strong> | <strong>S</strong>]</em>. We use a weighted geometric basket.</p><p>Let <em>S<sub>t</sub></em> denote the official S$NEER level in week <em>t</em>, and let <em>F<sub>t,i</sub></em> denote the normalized weekly-average value of SGD against currency <em>i</em>. We model the changes by differencing the sneer value:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Delta\\log S_t\n=\n\\sum_{i=1}^{n}w_i\\Delta\\log F_{t,i}\n+\\varepsilon_t.&quot;,&quot;id&quot;:&quot;FUGHILGUZM&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The residual <em>varepsilon<sub>t</sub></em> absorbs anything else not captured by our candidate universe.</p><p>Define the weekly S$NEER return</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_t=\\Delta\\log S_t,&quot;,&quot;id&quot;:&quot;DAPPXGACAW&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>and the vector of bilateral FX returns obtained from the first <em>n</em> columns of <em>&#119967;</em>,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_t=\n\\begin{bmatrix}\n\\Delta\\log F_{t,1} &amp;\n\\Delta\\log F_{t,2} &amp;\n\\cdots &amp;\n\\Delta\\log F_{t,n}\n\\end{bmatrix}^{\\top}.&quot;,&quot;id&quot;:&quot;ERNLBIAVRB&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Stacking <em>T</em> observations gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y=\n\\begin{bmatrix}\ns_1 &amp; s_2 &amp; \\cdots &amp; s_T\n\\end{bmatrix}^{\\top}\n\\in\\mathbb{R}^{T},&quot;,&quot;id&quot;:&quot;GWGLTAQZEJ&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>and</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;R=\n\\begin{bmatrix}\nr_1^{\\top}\\\\\nr_2^{\\top}\\\\\n\\vdots\\\\\nr_T^{\\top}\n\\end{bmatrix}\n\\in\\mathbb{R}^{T\\times n}.&quot;,&quot;id&quot;:&quot;XWHHQRTEWM&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The regression can then be written compactly as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y=Rw+\\varepsilon.&quot;,&quot;id&quot;:&quot;AXUCWXVMSE&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>An unconstrained least-squares estimator would solve</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat w_{OLS}\n=\n\\arg\\min_w\n\\lVert y-Rw\\rVert_2^2.&quot;,&quot;id&quot;:&quot;DEEVXYNRDL&quot;}" data-component-name="LatexBlockToDOM"></div><p>This may fit the historical S$NEER well while producing an economically implausible basket. The resulting weights may be negative or may not sum to one.</p><p>We know more about the object than ordinary least squares uses. Basket weights should be non-negative, and the complete basket should carry 100% weight. We therefore solve the restricted problem</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\widehat w\n=\\arg\\min_w\\quad\n&amp;\\lVert y-Rw\\rVert_2^2,\\\\\n\\text{subject to}\\quad\n&amp;w_i\\geq0,\\\\\n&amp;\\sum_{i=1}^{n}w_i=1.\n\\end{aligned}&quot;,&quot;id&quot;:&quot;BQVKENZJHM&quot;}" data-component-name="LatexBlockToDOM"></div><p>The feasible set is the probability simplex</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Delta_n\n=\n\\left\\{\nw\\in\\mathbb{R}^{n}:\nw_i\\geq0,\n\\mathbf{1}^{\\top}w=1\n\\right\\}.&quot;,&quot;id&quot;:&quot;QUDFZRVCGR&quot;}" data-component-name="LatexBlockToDOM"></div><p>The restrictions give the coefficients an immediate economic interpretation as basket weights.</p><h3>numerical solution (skip if not interested in the math)</h3><p>The squared-error objective</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f(w)=\\lVert y-Rw\\rVert_2^2&quot;,&quot;id&quot;:&quot;MMCRKYCTZA&quot;}" data-component-name="LatexBlockToDOM"></div><p>is convex, with gradient</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\nabla f(w)\n=\n2R^{\\top}(Rw-y).&quot;,&quot;id&quot;:&quot;IMHXDCCXVF&quot;}" data-component-name="LatexBlockToDOM"></div><p>We solve the constrained problem using projected gradient descent. From a feasible vector <em>w<sub>k</sub></em>, first take an unconstrained gradient step</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v_{k+1}\n=\nw_k-\\eta\\nabla f(w_k),&quot;,&quot;id&quot;:&quot;CLOSTRAUBA&quot;}" data-component-name="LatexBlockToDOM"></div><p>then project it back onto the simplex:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_{k+1}\n=\n\\Pi_{\\Delta_n}(v_{k+1}).&quot;,&quot;id&quot;:&quot;UWUQPCRQEC&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>The projection is itself the optimization problem</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Pi_{\\Delta_n}(v)\n=\n\\arg\\min_{w\\in\\Delta_n}\n\\frac{1}{2}\\lVert w-v\\rVert_2^2.&quot;,&quot;id&quot;:&quot;GWFXCSURHN&quot;}" data-component-name="LatexBlockToDOM"></div><p>Its solution has the form</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_i=\\max(v_i-\\theta,0),&quot;,&quot;id&quot;:&quot;DFXACHLVUF&quot;}" data-component-name="LatexBlockToDOM"></div><p>where <em>&#952;</em> is chosen such that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sum_{i=1}^{n}\\max(v_i-\\theta,0)=1.&quot;,&quot;id&quot;:&quot;BWQFFJDFML&quot;}" data-component-name="LatexBlockToDOM"></div><p>Intuitively, we subtract a common threshold from the unconstrained vector, set negative coordinates to zero, and choose the threshold so that the remaining weights sum to one.</p><p>We use the corresponding step size</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\eta\n=\n\\frac{1}{2\\lVert R\\rVert_2^2},&quot;,&quot;id&quot;:&quot;NBLQYZMSJY&quot;}" data-component-name="LatexBlockToDOM"></div><p>and stop when successive projected weight vectors are sufficiently close:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\lVert w_{k+1}-w_k\\rVert_2<\\epsilon.&quot;,&quot;id&quot;:&quot;TJWHCZAQSI&quot;}" data-component-name="LatexBlockToDOM"></div><h3>rolling estimation</h3><p>We estimate a separate basket for every observation week using the most recent <em>m=260</em> weekly returns, or approximately five years. This produces a sequence of models rather than one final model, which are the dynamic weights of the basket across time:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat w_{t_0},\n\\widehat w_{t_0+1},\n\\ldots,\n\\widehat w_T.&quot;,&quot;id&quot;:&quot;ADBOFPSEUJ&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><h3>predicting the S$NEER</h3><p>A model indexed by week <em>t</em> contains the official S$NEER observation for that week. We shift each fitted weight vector forward by one observation through the preceding observation, <em>w&#770;<sub>t-1</sub></em>, and multiply them by the current weekly FX-return vector <em>r<sub>t</sub></em>. The weighted sum is the predicted S$NEER log return. Applying that return to the previous official level gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat S_t\n=\nS_{t-1}\\exp\\left(\\widehat w_{t-1}^{\\top}r_t\\right).&quot;,&quot;id&quot;:&quot;WHOLNPEOZP&quot;}" data-component-name="LatexBlockToDOM"></div><p>How well do the previously estimated basket weights explain the next official weekly move?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sv8S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sv8S!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 424w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 848w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 1272w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sv8S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png" width="1456" height="730" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:730,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:404506,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/209479046?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Sv8S!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 424w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 848w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 1272w, https://substackcdn.com/image/fetch/$s_!Sv8S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa002b211-df16-4e13-a236-47ef73aa3156_2388x1198.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The actual and predicted levels lie almost on top of one another <strong>with a 0.972 correlation between the predicted and official weekly log returns, and a 5.07bps in weekly return RMSE.</strong></p><p>The fit is strong enough to treat the estimated basket as a useful S$NEER proxy. We have a number of remaining parameters to estimate.</p><h2>reconstructing the policy band</h2><p>MAS would make a brilliant X finfluencer, because they are experts in vague-posting. MAS summarises <a href="https://www.mas.gov.sg/monetary-policy/past-monetary-policy-decisions">monetary policy statements</a> in roughly this form:</p><pre><code><code>date          slope                 width                   centre
2018-04-13    Increase slightly     -                       -
2020-03-30    Set at 0%             -                       Re-centre downwards
2022-04-14    Increase slightly     -                       Re-centre upwards</code></code></pre><p>Our job is to translate qualitative policy language into a deterministic state machine. </p><p>Let <em>g</em> denote the annualized slope of the midpoint and let <em>h</em> denote the log half-width of the band. An unchanged field carries its previous value forward. Every other phrase updates one component of the policy state:</p><ul><li><p><strong>increase very slightly:</strong> <em>g &#8592; g+0.5&#948;</em></p></li><li><p><strong>increase slightly:</strong> <em>g &#8592; g+&#948;</em></p></li><li><p><strong>increase:</strong> <em>g &#8592; g+2&#948;</em></p></li><li><p><strong>reduce slightly:</strong> <em>g &#8592; max(0,g-&#948;)</em></p></li><li><p><strong>reduce:</strong> <em>g &#8592; max(0,g-2&#948;)</em></p></li><li><p><strong>set at 0%:</strong> <em>g &#8592; 0</em></p></li><li><p><strong>widen slightly:</strong> <em>h &#8592; 1.25h</em></p></li><li><p><strong>widen:</strong> <em>h &#8592; 1.5h</em></p></li><li><p><strong>restore narrower band:</strong> <em>h &#8592; h<sub>0</sub></em></p></li><li><p><strong>re-centre:</strong> reset the midpoint to the prevailing (predicted) <em>S&#771;<sub>d </sub></em></p></li></ul><p>The rules are symmetric. The zero floor prevents a sequence of reductions from implying a negative slope due to MAS slope policy since the outset.</p><p>We set one slope tick to <em>&#948;=0.5%</em> per annum, use a baseline log half-width of <em>h<sub>0</sub>=0.02</em>, or approximately 2% on either side of the midpoint, and anchor the April initial slope at 2% per annum. </p><p>This is aligned with the UOB&#8217;s paper. Once these values are fixed, the same rules are applied across the entire time series; there is no additional parameter fitting.</p><h3>evolving the midpoint</h3><p>Let <em>M<sub>d</sub></em> be the policy midpoint on day <em>d</em>. Between re-centring decisions, its log level accumulates the prevailing annualized slope:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\log M_d\n=\n\\log M_{d-1}\n+\ng_{d-1}\\Delta\\tau_d,&quot;,&quot;id&quot;:&quot;PDAUEDEELE&quot;}" data-component-name="LatexBlockToDOM"></div><p>where <em>&#916;&#964;<sub>d</sub></em> is the fraction of a year elapsed since the preceding observation. On a re-centring date, we reset <em>M<sub>d</sub></em> to the prevailing reconstructed S$NEER and continue accumulating drift from the new base.</p><p>The upper and lower boundaries are then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;L_d=M_d\\exp(-h_d),\n\\qquad\nU_d=M_d\\exp(h_d).&quot;,&quot;id&quot;:&quot;XQRLXZDWFV&quot;}" data-component-name="LatexBlockToDOM"></div><p>Using a geometric band keeps both boundaries positive and makes widening symmetric in log-return space.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cuJ2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cuJ2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 424w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 848w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cuJ2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png" width="1456" height="729" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:729,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1037331,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/209479046?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cuJ2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 424w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 848w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!cuJ2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F001d3e88-d44b-4ce6-b19f-e95fd9f06f7b_2378x1190.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We have now constructed a parsimonious model calibrated against a deterministic state machine, and verified that results are somewhat in line with a reputable bank. If we are economist, we would be happy, but as traders, we make no money from this&#8230;</p><p>But how may we construct a continuous portfolio from this?</p><h3>portfolio construction</h3>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-e4c">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[HFT - Event Journaling and Quantpylib's Native Journaling Architecture]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com/p/hft-event-journaling-and-quantpylibs</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/hft-event-journaling-and-quantpylibs</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Tue, 28 Jul 2026 16:50:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!m2hC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In software, an event journal is an ordered, append-only record of state transitions accepted by a system. In a HFT trading system, it provides a durable account of important in-memory states such as order state transitions, fills, position deltas, and portfolio snapshots. It records details such as </p><ul><li><p>when an order was created locally and sent into the wire</p></li><li><p>when the order arrived at the exchange</p></li><li><p>when the order-ack was received locally</p></li><li><p>and all other state transitions.</p></li></ul><p>These artefacts can be used downstream for a number of important business functions such as</p><ul><li><p>latency analysis;</p></li><li><p>slippage analysis;</p></li><li><p>markout and adverse-selection analysis;</p></li><li><p>tick-to-trade shortfall;</p></li><li><p>trading-cost attribution; and</p></li><li><p>reconciliation and incident replay.</p></li></ul><p>Event journalling is a core component of replay fidelity. A replay recovers the order in which the live process observed and accepted state changes. A journal lets us rebuild those transitions.</p><p></p><h4><strong>We are running 1-week of discounts of access to Quantpylib:</strong></h4><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;23b91969-7d13-4af0-bdd6-b11e9cbb09ce&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Introduce, the QuantTerminal&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-26T16:26:27.442Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Mrz_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/introduce-the-quantterminal&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:208298022,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:9,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p><strong>In this article,</strong> we give a rundown of quantpylib&#8217;s native binary event-journal architecture and how to use it, including the Quantpylib Event Trace (QET) compiler. We will also show how quantpylib users can produce QET trace files directly from an OMS workflow.</p><h2>Artefacts</h2><p>In quantpylib, the following portfolio artefacts are journaled:</p><ul><li><p>order state changes;</p></li><li><p>fill insertions;</p></li><li><p>position deltas;</p></li><li><p>order snapshots; and</p></li><li><p>position snapshots.</p><p></p></li></ul><p>We will use an order lifecycle as the running example. Consider the following HYPE limit order:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;c7e20f0d-482c-4ebe-954d-bea36591d911&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from decimal import Decimal


order = {
    "exc": "hyperliquid",
    "ticker": "HYPE",
    "amount": Decimal("1"),
    "price": Decimal("20"),
    "tif": "Alo",
    "cloid": oms.rand_cloid(exc="hyperliquid"),
}

await oms.limit_order(**order)</code></pre></div><p>The OMS first constructs the exchange-native order wire. Before submitting that wire, it inserts the order into its in-memory <code>Orders</code> ledger with a <code>CREATE_PENDING</code> status and a local <code>ts_submit_ns</code>. At this point the client order ID (<code>cloid</code>) is known, but the exchange order ID (<code>oid</code>) usually is not. </p><p>When an update arrives through the private order WebSocket, the ledger resolves the order by <code>cloid</code> or <code>oid</code> and applies its staleness and identity checks. A successful acknowledgement will typically complete the identity with an <code>oid</code> and transition the order to <code>NEW</code>. A rejected submission transitions to <code>REJECTED</code>. Later updates may move a live order through <code>PARTIAL</code> and <code>FILLED</code>, or through <code>CANCEL_PENDING</code> and <code>CANCELLED</code> when we attempt a cancellation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bGO0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bGO0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bGO0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Order lifecycle and binary QET trace&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Order lifecycle and binary QET trace" title="Order lifecycle and binary QET trace" srcset="https://substackcdn.com/image/fetch/$s_!bGO0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!bGO0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1801dd5f-513f-4220-b851-9fc6cd028cba_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The diagram is deliberately simplified. The exact path depends on the venue and execution outcome.</p><p>For the <code>CREATE_PENDING</code> order above, the in-memory object and its trace artefact look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!az6m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!az6m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!az6m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!az6m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!az6m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!az6m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;In-memory order encoded as a binary QET trace&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="In-memory order encoded as a binary QET trace" title="In-memory order encoded as a binary QET trace" srcset="https://substackcdn.com/image/fetch/$s_!az6m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!az6m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!az6m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!az6m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a6b521-687e-4c85-922f-9cde45789b66_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><code>S</code><span> identifies the trading session, while </span><code>N</code><span> is the session&#8217;s trace sequence number. Based on the state machine, the appropriate events. such as </span><code>trace.orders.insert</code><span>, </span><code>trace.orders.state_transition</code><span> is created.</span></p><p><strong><span>These actions occur in the trading hot path, so an inefficient transport would make the journal unusable. The trace artefact is compactly encoded as raw bytes and handed to quantpylib's high performance logging subsystem.</span></strong><span> </span></p><p><span>The transport is therefore a native C++ implementation adapted into byte buffers over the LMAX Disruptor pattern, exposed in Python.</span></p><p><span>Read the design here: </span><a href="https://www.research.hangukquant.com/p/designing-state-of-the-art-logging">Designing State-of-the-Art Logging in Python</a><span>. </span></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;5575423b-a20d-4776-a642-a11f9ddb2c03&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Designing State-of-the-Art Logging in Python&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-05-08T12:55:55.552Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!NdZd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/designing-state-of-the-art-logging&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:196889438,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:15,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><span>Insofar as the trading system is concerned, the trace is complete. This makes the trace subsystem a lightweight attachment (a normal logging statement) and non-intrusively composed with client applications.</span></p><p></p><h2>QET Compilation</h2><p>Once the logging hand-off is complete, the log file receives JSONL records of the following shape.</p><pre><code><code>{"level": "INFO", "time": "2026-07...", "message": "trace", "event": "trace.orders.insert", "trace": "qwAAAAMAAAAHAAAA...VzAw"}</code></code></pre><p><code>event</code> identifies the accepted mutation. <code>trace</code> is the original binary artefact, base64-encoded. Trace records and ordinary application logs may share the same file.</p><p>An event journal can be attached directly to a live trading system. <strong>quantpylib instead uses the log files as the substrate and compiles QET files in a separate, cold process.</strong> </p><p>The trading process is finished once it hands the record to the logger; parsing, ordering, deduplication, and journal I/O remain outside the live system.</p><p>Many firms already operate some form of the Grafana logging stack. <a href="https://grafana.com/docs/alloy/latest/">Grafana Alloy</a> acts as the collector. The usual destination is <a href="https://grafana.com/docs/loki/latest/">Grafana Loki</a>, which stores compressed log chunks and indexes their labels for later queries.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m2hC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m2hC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 424w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 848w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 1272w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m2hC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png" width="1456" height="592" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:592,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;quantpylib binary event journal pipeline&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="quantpylib binary event journal pipeline" title="quantpylib binary event journal pipeline" srcset="https://substackcdn.com/image/fetch/$s_!m2hC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 424w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 848w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 1272w, https://substackcdn.com/image/fetch/$s_!m2hC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c92a4a5-6d3f-49f8-a3ee-acd8c51ce1a9_1672x680.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>quantpylib piggybacks on this battle-tested transport. We configure Alloy to push the same records to our compiler's Loki-compatible endpoint:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b20f4de7-5474-49c4-8d73-ce1f920efd21&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">loki.write "qet_compiler" {
  endpoint {
    url = "http://127.0.0.1:33200/loki/api/v1/push"
  }
}</code></pre></div><p>This can be the sole destination or added to an existing Alloy pipeline.</p><p><span>The compiler is a small local HTTP service that implements the Loki push API. It decompresses each Snappy-compressed protobuf batch, recovers the original JSON line, filters trace records, base64-decodes the trace, and validates the QET schema and record length. </span></p><p><span>The Loki entry timestamp selects the UTC output day; the trace's </span><code>sid</code><span> and </span><code>seqno</code><span> is used for ordering and idempotence. The compiler then appends the original binary records to a daily </span><code>.qet</code><span> file.</span></p><h2>Example</h2><p>Here we will give a walkthrough of how to wire them together.</p><p>Install Alloy using Grafana&#8217;s <a href="https://grafana.com/docs/alloy/latest/set-up/install/">platform instructions</a>. The Alloy CLI command reference is <a href="https://grafana.com/docs/alloy/latest/reference/cli/">here</a>.</p><h3>1. start the compiler</h3><pre><code><code>python3.11 -m quantpylib.hft.qet_compiler serve \
  --root ./qet \
  --host 127.0.0.1 \
  --port 33200 \
  --buffer-size 48</code></code></pre><p>Check its counters from another terminal:</p><pre><code><code>curl http://127.0.0.1:33200/health</code></code></pre><h3>2. start Alloy</h3><p><code>examples/configs.alloy</code> (<a href="https://github.com/hangukquant/quantpylib/blob/main/examples/configs.alloy">quantpylib</a>) points Alloy at an absolute log glob and at the local compiler. Point Alloy at the file written by the example in step 3:</p><pre><code><code>export QUANTPYLIB_LOG_PATH="$(pwd)/logs/journal.log"

alloy validate examples/configs.alloy
alloy run --storage.path=./.alloy-data examples/configs.alloy</code></code></pre><h3>3. run the example</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;8a49c3e2-0af9-42b4-bf6d-ef68d7cc6d32&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import os
import asyncio
import logging
from decimal import Decimal

from dotenv import load_dotenv

from quantpylib.hft.oms import OMS
from quantpylib.logger import Logger
from quantpylib.gateway.master import Gateway


load_dotenv()

exchange = "bybit"
ticker = "HYPEUSDT"
amount = Decimal("1")
price = Decimal("10")

async def main():
    gateway = Gateway({
        exchange: {
            "key": os.environ["TEST_BYBIT_KEY"],
            "secret": os.environ["TEST_BYBIT_SECRET"],
        },
    })
    await gateway.init_clients()

    os.makedirs("logs", exist_ok=True)
    logger = Logger(
        name="perf",
        stdout_register=True,
        filename="journal.log",
        logs_dir="./logs",
        file_level=logging.INFO,
    )

    oms = OMS(gateway, logger=logger)

    try:
        await oms.init()
        cloid = oms.rand_cloid(exc=exchange)
        res = await oms.limit_order(
            exc=exchange,
            ticker=ticker,
            amount=amount,
            price=price,
            cloid=cloid,
        )
        print(res)
        await asyncio.sleep(5)

        res = await oms.cancel_order(exc=exchange, ticker=ticker, cloid=cloid)
        print(res)
    finally:
        await oms.cleanup()
        logger.shutdown()

if __name__ == "__main__":
    asyncio.run(main())</code></pre></div><p>In <code>journal.log</code> we see one insert and three state transitions, corresponding to create, create-ack, cancel, and cancel-ack. We also see snapshots, which allow recovery when a new session begins.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f4902047-3c53-48d9-9abc-6e70fa728da8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{"ts":"2026-07-26 17:15:25.642","level":"INFO","filename":"portfolio.py","line":1157,"msg":"trace","event":"trace.orders.snapshot","trace":"b'...'"}
{"ts":"2026-07-26 17:15:25.766","level":"INFO","filename":"portfolio.py","line":408,"msg":"trace","event":"trace.positions.snapshot","trace":"b'...'"}
{"ts":"2026-07-26 17:15:25.965","level":"INFO","filename":"portfolio.py","line":1354,"msg":"trace","event":"trace.orders.insert","trace":"b'...'"}
{"ts":"2026-07-26 17:15:25.998","level":"INFO","filename":"portfolio.py","line":1354,"msg":"trace","event":"trace.orders.state_transition","trace":"b'...'"}
{"ts":"2026-07-26 17:15:31.000","level":"INFO","filename":"portfolio.py","line":1354,"msg":"trace","event":"trace.orders.state_transition","trace":"b'...'"}
{"ts":"2026-07-26 17:15:31.093","level":"INFO","filename":"portfolio.py","line":1354,"msg":"trace","event":"trace.orders.state_transition","trace":"b'...'"}</code></pre></div><p>Inspect the generated qet file here:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;103362a8-db64-448e-9eb8-3119f173ca0c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from pathlib import Path

from quantpylib.hft.qet import QETReader, QET_SCHEMA_REGISTRY


path = sorted(Path("qet").glob("*.qet"))[-1]
reader = QETReader(path)

for event in reader.decoded_records():
    event_type = QET_SCHEMA_REGISTRY[event["schema_id"]].partition("(")[0]
    print(event["sid"], event["seqno"], event_type)</code></pre></div><p><span>which gives me the following traces:</span></p><pre><code>92375019 0 QETOrdersSnapshot
92375019 1 QETPositionsSnapshot
92375019 2 QETOrder
92375019 3 QETOrder
92375019 4 QETOrder
92375019 5 QETOrder</code></pre>]]></content:encoded></item><item><title><![CDATA[Introduce, the QuantTerminal]]></title><link>https://www.research.hangukquant.com/p/introduce-the-quantterminal</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/introduce-the-quantterminal</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Sun, 26 Jul 2026 16:26:27 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Mrz_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>3 years ago, we launched the quantpylib repo.</strong> The goal was to enable quantitative research and trading workflows for quants. Over the years, traders have used the library to research and deploy all sorts of strategies, from loose-pants trend following to complex market-making systems. </p><p>I myself have used quantpylib&#8217;s crypto wrappers on dexs, prediction markets et cetera in latency sensitive workflows to <strong>generate more than $1M in market making pnl, and more than $1B in volume driving my quantitative research and strategies.</strong></p><p>The library allows developers to assimilate into their own trading pipeline, allowing sophisticated traders to use it&#8217;s well-abstracted features at the appropriate layer, whether it is for risk management, offline research, or live trading. </p><p><strong>Today, we announce the QuantTerminal, which gives a face to Quantpylib&#8217;s core features - this will give quant teams an interface and access to end-end applications of the best and most powerful workflows possible in Quantpylib.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mrz_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mrz_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 424w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 848w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mrz_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png" width="290" height="290" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/850adc34-8c05-4836-b523-d7842311e611_1254x1254.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1254,&quot;width&quot;:1254,&quot;resizeWidth&quot;:290,&quot;bytes&quot;:1107866,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/208298022?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Mrz_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 424w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 848w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!Mrz_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F850adc34-8c05-4836-b523-d7842311e611_1254x1254.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Target Core features</h3><ul><li><p>Live, multi-exchange Tick Data Terminal</p></li><li><p>Live, multi-exchange position and Order Tracking</p></li><li><p>Tick Data Lake Archival and Session Replay</p></li><li><p>Binary Order Event Trace for HFT Market Making</p></li><li><p>Quantitative Analytics for Order Execution (markouts, slippage, latency etc)</p></li><li><p>Live Telemetry</p></li><li><p>and more!</p></li></ul><p>This is an <strong>internal quant tooling system</strong> we&#8217;ve been sitting on, and we have decided to do a staged rollout of it. We understand that quant teams need to own their IPs - code and data are sacred. Therefore, the terminal application is transparent software that is intended to be run locally on your own workstation - with your own data. <strong>It&#8217;s powered by quantpylib, therefore access to the library is a prerequisite.</strong></p><p>First stage of the rollout is the <strong>live terminal view</strong>. Here is a short 30-sec demo. </p><div id="youtube2-ibAkft1yO2E" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;ibAkft1yO2E&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/ibAkft1yO2E?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Note that it&#8217;s in a beta-stage rollout, and priced as such. As we continue to rollout, we will increase the price of the access pass accordingly.</p><h3>Access, Quantpylib 1 Week Discount</h3><p style="text-align: center;">The QuantTerminal access pass is available here:<br><a href="https://quantpylib.hangukquant.com/pricing/pricing/">https://quantpylib.hangukquant.com/pricing/pricing/</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CFxP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CFxP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 424w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 848w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 1272w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CFxP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png" width="1306" height="822" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:822,&quot;width&quot;:1306,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:179293,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/208298022?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CFxP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 424w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 848w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 1272w, https://substackcdn.com/image/fetch/$s_!CFxP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1575a67-09fa-40dc-98db-e5871b0416f9_1306x822.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For one week, we are running discounted access to Quantpylib. Running QuantTerminal requires access to the Quantpylib library.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 3.1: event driven arbitrage)]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-12a</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-12a</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 24 Jul 2026 11:51:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3nb5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febd8b20b-01f7-4bc9-b498-d8bd3375074c_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Prediction markets have attracted considerable attention over the past year, driven by the proliferation of exchanges, liquidity venues and increasingly creative contracts. Pricing theory around many of these contracts remains nascent, and outsized opportunities still exist while more conventional market makers find their footing.</p><p>I have traded more than $100 million in volume across these platforms, generating more than $1 million in PnL. My operations have primarily revolved around three strategy families:</p><ul><li><p>cross-exchange, combinatorial and statistical arbitrage;</p></li><li><p>event-driven arbitrage;</p></li><li><p>high-frequency market making.</p></li></ul><p><strong>The first family</strong> is somewhat capacity-constrained. Liquidity remains shallow across many nascent venues, and seemingly identical contracts are not necessarily fungible. Two exchanges may list economically similar questions while using different resolution sources, deadlines, wording or discretionary procedures. What looks like a locked arbitrage can therefore contain rather more basis risk. In fact, as I write this post, here is an obvious one between poly and hpl.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jot9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jot9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 424w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 848w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jot9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png" width="552" height="608.0266222961731" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1324,&quot;width&quot;:1202,&quot;resizeWidth&quot;:552,&quot;bytes&quot;:523536,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/208021198?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jot9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 424w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 848w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!Jot9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F457c22c9-6ab6-44e1-8c85-ab11c45ae319_1202x1324.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p> </p><p><strong>The second family</strong> is considerably more scalable, but requires serious thought around engineering processes. I ran reduced-form versions of these strategies in the past before eventually pausing them. Too many parts of the system were &#8220;non-automatable&#8221;: particularly around sourcing new contracts, registering new data sources et-cetera.</p><p><strong>Recent improvements in agentic systems&#8212;particularly following GPT5.5 and Opus4.8 make the problem interesting again in my opinion.</strong></p><p><strong>The third strategy</strong> family, high-frequency market making, is the most scalable of the three. It also requires proper domain expertise, quantitative reasoning and a reasonably intimate understanding of exchange microstructure. This is what placed me near the top of the relevant leaderboards in terms of both volume and PnL.</p><p>We have, in fact, documented an entire lecture series detailing the design and implementation of my HFT ops, to be later posted <a href="https://lectures.hangukquant.com/">here</a>.</p><p>It will not be released until yours truly is no longer involved in said markets.</p><p>For now, we will focus on event-driven arbitrage. Our discussion here will take a more <em>idealistic approach compared to what I ran</em>, accounting for the scalability now possible under accelerated agentic capabilities. The objective is a pipeline capable of serving hundreds to thousands, of prediction-market contracts.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-12a">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 2: trading in factor space)]]></title><description><![CDATA[factor-trading in crypto, with code]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-3df</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-3df</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Sat, 18 Jul 2026 16:37:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!haFO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><span>PSA: we have an </span><strong><span>ongoing, 1-week 50% discount on all subs.</span></strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;6348eed7-19a9-4e1b-9995-3cec21d46526&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Quantitative Trading Strategies - How I went from 10k to 100k to 1M (new series intro)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-13T15:27:14.056Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!XNBn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/quantitative-trading-strategies-how&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:206797572,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:17,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p><strong>A</strong> factor model is motivated by the observation that market movements are primarily driven by a relatively small number of common sources of risk. Assets may have thousands of individual return streams, but much of their variation is shared: broad market movements, industries, economic characteristics, liquidity conditions, or latent statistical relationships. The purpose of a factor model is to separate these common movements from asset-specific noise.</p><p>There are three broad approaches: <strong>Fama-style (time-series) portfolio factors</strong>, <strong>statistical factor models such as PCA</strong>, and <strong>Barra-style (cross-sectional) exposure models</strong>. They differ not merely in interpretation, but in the direction of estimation, the information supplied to the model, and the quantity being estimated.</p><p>Getting timely exposure to desirable factors &#8212; and hedging undesirable ones &#8212; is a primary concern of smart-beta funds and are a TRILLION dollar industry. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!haFO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!haFO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 424w, https://substackcdn.com/image/fetch/$s_!haFO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 848w, https://substackcdn.com/image/fetch/$s_!haFO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 1272w, https://substackcdn.com/image/fetch/$s_!haFO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!haFO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp" width="1456" height="399" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:399,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25172,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206813161?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!haFO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 424w, https://substackcdn.com/image/fetch/$s_!haFO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 848w, https://substackcdn.com/image/fetch/$s_!haFO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 1272w, https://substackcdn.com/image/fetch/$s_!haFO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd713ca0e-cf3d-4137-a399-d0a3ccaa3601_1456x399.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Factor analysis in crypto is still nascent. This article focuses on Barra-style models and how I actively trade them to enhance my pnl. </p><p><strong>The full implementation is included at the bottom.</strong></p><p>We will touch lightly on the first two, and then detail a Barra-style analysis with code.</p><h2>Fama-style</h2><p>A Fama-style factor is defined as the return of a portfolio. For example, a simplified value factor might be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{value},t}\n=\nR_{\\mathrm{high\\ value},t}\n-\nR_{\\mathrm{low\\ value},t}.&quot;,&quot;id&quot;:&quot;OWHEQIPCCJ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>More generally, if (<em>p<sub>k,t</sub></em>) contains the asset weights of factor portfolio (<em>k</em>), then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{k,t}=p_{k,t}'R_t.&quot;,&quot;id&quot;:&quot;KFQEYMHZGS&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Once these factor-return histories have been constructed, the <strong>exposure of an individual asset is estimated through time:</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\underbrace{r_i}_{T\\times1}\n=\n\\alpha_i\\mathbf 1\n+\n\\underbrace{F}_{T\\times K}\n\\underbrace{\\beta_i}_{K\\times1}\n+\n\\epsilon_i.&quot;,&quot;id&quot;:&quot;GCBDFAFQZK&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The factor-return matrix (<em>F</em>) is known. The regression estimates (<em>&#946;<sub>i</sub></em>):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat{\\beta}_i\n=\n(F'F)^{-1}F'r_i.&quot;,&quot;id&quot;:&quot;WHVDMMNGRW&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>For a single, demeaned factor,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat{\\beta}_i\n=\n\\frac{\\operatorname{Cov}(r_i,f)}\n{\\operatorname{Var}(f)}.&quot;,&quot;id&quot;:&quot;EGDMXSSQZH&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p><strong>Fama-style models are motivated by economic hypotheses about expected returns.</strong> Is a manager&#8217;s apparent alpha simply compensation for exposure to known factor strategies? Is our portfolio (statistically) significantly just some beta against a factor portfolio?</p><p>For a portfolio with estimated factor betas (<em>&#946;<sub>p</sub></em>),</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\operatorname{Var}(r_p)\n=\n\\beta_p'\\Sigma_F\\beta_p\n+\n\\sigma_{\\epsilon,p}^2.&quot;,&quot;id&quot;:&quot;AUDVSIVIFD&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><h2>Statistical-style</h2><p>A statistical factor model begins with the complete return matrix:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;R\\in\\mathbb R^{T\\times N},&quot;,&quot;id&quot;:&quot;YWPMZDWBBF&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>where rows are dates and columns are assets. It seeks a lower-dimensional approximation:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;R\\approx FL'+E,&quot;,&quot;id&quot;:&quot;NGCRPYEPMF&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>where <em>F</em> &#8712; &#8477;<sup>T&#215;K</sup> contains the statistical factor returns and <em>L</em> &#8712; &#8477;<sup>N&#215;K</sup> contains the asset loadings. In principal components analysis, first estimate the asset covariance matrix:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma_R\n=\n\\frac{1}{T-1}R'R,&quot;,&quot;id&quot;:&quot;IWCFZNNDRS&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>of demeaned returns. Decompose it as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma_R=V\\Lambda V'.&quot;,&quot;id&quot;:&quot;UUOTIICYLG&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The first (<em>K</em>) eigenvectors define the principal directions:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V_K=\n\\begin{bmatrix}\nv_1 &amp; \\cdots &amp; v_K\n\\end{bmatrix},&quot;,&quot;id&quot;:&quot;JGQVTGGNZZ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>and the corresponding factor scores are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;F=RV_K.&quot;,&quot;id&quot;:&quot;ECLAFNMGFZ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The resulting rank-(<em>K</em>) reconstruction is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;R\\approx FV_K'.&quot;,&quot;id&quot;:&quot;PSRNDHKIOD&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Unlike the Fama regression, however, neither the factors nor the loadings are specified economically. </p><p>These are <strong>motivated mainly by dimensionality reduction</strong>. If hundreds of assets share a few dominant covariance patterns, the researcher may want to discover those patterns without imposing characteristic taxonomy.</p><p><a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3530390">Here is a seminal paper on enhanced portfolio optimization using principal components by AQR&#8217;s Pedersen et al.</a></p><h2>Barra-style </h2><p>The focus of our post, is the Barra-style model. We will first discover it&#8217;s mathematical basis, and then use them to identify sector performance.</p><p>We begin by specifying each asset&#8217;s exposures. On date (<em>t</em>),</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;B_t\\in\\mathbb R^{N\\times K}&quot;,&quot;id&quot;:&quot;CVZWMANRQF&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>contains exposures to K factors, such as categories, industries, countries, or continuous styles such as size and momentum.</p><p>The model then examines the <strong>cross-section of asset returns on that date:</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\underbrace{R_t}_{N\\times1}\n=\n\\underbrace{B_t}_{N\\times K}\n\\underbrace{f_t}_{K\\times1}\n+\n\\epsilon_t.&quot;,&quot;id&quot;:&quot;GDAPQLMLIY&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The <strong>exposures (</strong><em><strong>B<sub>t</sub></strong></em><strong>) are known. The factor returns (</strong><em><strong>f<sub>t</sub></strong></em><strong>) are estimated</strong> using the (<em>N</em>) assets observed on that date. </p><p><strong>This regression is repeated for every date, therefore produces a time series of factor returns from a sequence of cross-sectional regressions.</strong></p><p>Barra-style models are motivated by the need to describe the current economic composition of a portfolio. Rather than waiting for a long return history to reveal a portfolio&#8217;s betas, the manager declares or measures the underlying asset exposures directly.</p><p>Repeating the cross-sectional regression each day produces a synthetic return series for every factor. By extension, if sector inclusion is defined as a factor, we obtain the synthetic return of the sector performance.</p><p>They are useful to:</p><ul><li><p>portfolio managers performing return attribution;</p></li><li><p>risk managers estimating common and specific risk;</p></li><li><p>traders neutralising unwanted industry or style bets;</p></li><li><p><em><strong>isolating sector performance for smart beta plays.</strong></em></p><p></p></li></ul><p>The factor return has a different meaning from a Fama-style factor. It is the return attributed to one unit of exposure after controlling for the other exposures in the cross-sectional regression. </p><h2>Example'; crypto Barra model</h2><p>We will demonstrate the categorical Barra analysis here using a reduced four-asset problem with two categories. The full regression code can be found at the bottom.</p><p>Let&#8217;s begin.</p><p>Suppose our universe contains four assets:</p><ul><li><p><strong>BTC</strong> &#8212; L1; daily return 4%; liquidity score 4.</p></li><li><p><strong>ETH</strong> &#8212; L1; daily return 2%; liquidity score 2.</p></li><li><p><strong>DOGE</strong> &#8212; Meme; daily return 8%; liquidity score 1.</p></li><li><p><strong>PEPE</strong> &#8212; Meme; daily return 6%; liquidity score 1.</p></li></ul><p>The objective is to estimate three returns:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_t=\n\\begin{bmatrix}\nf_{\\mathrm{market},t}\\\\\nf_{\\mathrm{L1},t}\\\\\nf_{\\mathrm{Meme},t}\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;BCJOCGUSMY&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The market factor represents the weighted return of the crypto universe. The category factors represent L1 and Meme performance relative to that market.</p><h3>1. Construct the return vector</h3><p>For each asset, the daily close-to-close return is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_{i,t}\n=\n\\frac{P_{i,t}}{P_{i,t-1}}-1.&quot;,&quot;id&quot;:&quot;QBHNFWAGXO&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Collect the four asset returns into the vector</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y_t=\n\\begin{bmatrix}\nr_{\\mathrm{BTC},t}\\\\\nr_{\\mathrm{ETH},t}\\\\\nr_{\\mathrm{DOGE},t}\\\\\nr_{\\mathrm{PEPE},t}\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;PICTAWXKGC&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>This is the dependent variable in the daily cross-sectional regression.</p><h3>2. Construct the regression weights</h3><p>For each day, determine asset&#8217;s regression weight. Reasonably, we may choose the square root of its preceding 30-day dollar volume:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;q_{i,t}\n=\n\\sqrt{\n\\sum_{\\tau=t-30}^{t-1}\nP_{i,\\tau}V_{i,\\tau}\n}.&quot;,&quot;id&quot;:&quot;BTZLISHCRN&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The weights are then normalised:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_{i,t}\n=\n\\frac{q_{i,t}}{\\sum_jq_{j,t}}.&quot;,&quot;id&quot;:&quot;KGTMRPAHKA&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Our simplified liquidity scores are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;q=\n\\begin{bmatrix}\n4\\\\\n2\\\\\n1\\\\\n1\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;OVTZPSPRBJ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Since they sum to eight, the normalised weights are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w=\n\\begin{bmatrix}\n0.50\\\\\n0.25\\\\\n0.125\\\\\n0.125\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;XDBQMSUDHR&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The WLS weighting matrix is simply diag(w).</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;W=\n\\begin{bmatrix}\n0.50&amp;0&amp;0&amp;0\\\\\n0&amp;0.25&amp;0&amp;0\\\\\n0&amp;0&amp;0.125&amp;0\\\\\n0&amp;0&amp;0&amp;0.125\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;ZGEIEQKAJD&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>BTC contributes half of the regression weight, ETH contributes one quarter, and DOGE and PEPE each contribute one eighth.</p><h3>3. Construct the exposure matrix</h3><p>Every asset has market exposure equal to one. It also has exposure equal to one to its assigned category.</p><p>The exposure matrix is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X=\n\\begin{bmatrix}\n1&amp;1&amp;0\\\\\n1&amp;1&amp;0\\\\\n1&amp;0&amp;1\\\\\n1&amp;0&amp;1\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;PAYGCVVLQN&quot;}" data-component-name="LatexBlockToDOM"></div><p>for columns [market, L1, Meme] and rows [BTC, ETH, DOGE, PEPE].</p><p>Each day, the regression equation is given by (solve for <em>f</em>)</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y=Xf+\\epsilon.&quot;,&quot;id&quot;:&quot;XENVCEVQOK&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>For instance,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_{\\mathrm{BTC}}\n=\nf_{\\mathrm{market}}\n+\nf_{\\mathrm{L1}}\n+\n\\epsilon_{\\mathrm{BTC}},&quot;,&quot;id&quot;:&quot;LEXXVGZVHO&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_{\\mathrm{PEPE}}\n=\nf_{\\mathrm{market}}\n+\nf_{\\mathrm{Meme}}\n+\n\\epsilon_{\\mathrm{PEPE}}.&quot;,&quot;id&quot;:&quot;PHVXMGIXBC&quot;}" data-component-name="LatexBlockToDOM"></div><p>The model assigns the same fitted common return to assets in the same category. Differences between the individual asset returns in a fitted category return remain in the residuals.</p><h3>4. Remove collinearity problem</h3><p>The market column is equal to the sum of the two category columns:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X_{\\mathrm{market}}\n=\nX_{\\mathrm{L1}}\n+\nX_{\\mathrm{Meme}}.&quot;,&quot;id&quot;:&quot;OODGHFBWJN&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Consequently, the exposure matrix does not have full column rank.</p><p>For a particular solution</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\left(\nf_{\\mathrm{market}},\nf_{\\mathrm{L1}},\nf_{\\mathrm{Meme}}\n\\right)&quot;,&quot;id&quot;:&quot;XTLXQUXLYI&quot;}" data-component-name="LatexBlockToDOM"></div><p>and any constant <em>a</em>,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\left(\nf_{\\mathrm{market}}+a,\nf_{\\mathrm{L1}}-a,\nf_{\\mathrm{Meme}}-a\n\\right)&quot;,&quot;id&quot;:&quot;OPZSQNZXQI&quot;}" data-component-name="LatexBlockToDOM"></div><p>produces exactly the same fitted asset returns.</p><p><strong>We</strong> <strong>may solve this by requiring the liquidity-weighted average category return to equal zero.</strong></p><h3>5. Reduction of Degree of Freedom</h3><p>Let the aggregate weight of <strong>category </strong><em><strong>c</strong></em> be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_c\n=\n\\sum_{i\\in c}w_i.&quot;,&quot;id&quot;:&quot;PSNVLEZTHV&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>In our example,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_{\\mathrm{L1}}\n=\n0.50+0.25\n=\n0.75&quot;,&quot;id&quot;:&quot;YVQVVZUCNE&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_{\\mathrm{Meme}}\n=\n0.125+0.125\n=\n0.25.&quot;,&quot;id&quot;:&quot;VKQFDSAVEW&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>We impose</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_{\\mathrm{L1}}f_{\\mathrm{L1}}\n+\ns_{\\mathrm{Meme}}f_{\\mathrm{Meme}}\n=\n0.&quot;,&quot;id&quot;:&quot;FAXLYRNJTU&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Substituting the category weights,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.75f_{\\mathrm{L1}}\n+\n0.25f_{\\mathrm{Meme}}\n=\n0.&quot;,&quot;id&quot;:&quot;IJXQFJUWVX&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The constraint vector is therefore</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c=\n\\begin{bmatrix}\n0\\\\\n0.75\\\\\n0.25\n\\end{bmatrix},&quot;,&quot;id&quot;:&quot;YQEPOJNSFL&quot;}" data-component-name="LatexBlockToDOM"></div><p>and the constraint is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c'f=0.&quot;,&quot;id&quot;:&quot;XXHCZBOAGU&quot;}" data-component-name="LatexBlockToDOM"></div><p><strong>The leading zero means that the market coefficient is not directly constrained.</strong> </p><p></p><h3>6. Solving the constrained WLS</h3><p>We minimise the weighted squared residuals:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat f\n=\n\\arg\\min_f\n\\frac{1}{2}\n(y-Xf)'W(y-Xf)&quot;,&quot;id&quot;:&quot;VCBVGXWLJS&quot;}" data-component-name="LatexBlockToDOM"></div><p>subject to</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c'f=0.&quot;,&quot;id&quot;:&quot;DCTQOZMNGV&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Introduce a Lagrange multiplier <em>&#955;</em>:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal L(f,\\lambda)\n=\n\\frac{1}{2}\n(y-Xf)'W(y-Xf)\n+\n\\lambda c'f.&quot;,&quot;id&quot;:&quot;RIDVVOOJIQ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The first-order condition with respect to <em>f</em> is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;-X'W(y-Xf)+c\\lambda=0.&quot;,&quot;id&quot;:&quot;ORYSDZAPIN&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Rearranging,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X'WXf+c\\lambda=X'Wy.&quot;,&quot;id&quot;:&quot;ZJMNPBZBKM&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The first-order condition with respect to <em>&#955;</em> is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c'f=0.&quot;,&quot;id&quot;:&quot;IXSQGTNODF&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Combining the two equations produces the KKT system:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{bmatrix}\nX'WX&amp;c\\\\\nc'&amp;0\n\\end{bmatrix}\n\\begin{bmatrix}\n\\widehat f\\\\\n\\lambda\n\\end{bmatrix}\n=\n\\begin{bmatrix}\nX'Wy\\\\\n0\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;BTVELVIGRW&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>For our example,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X'WX\n=\n\\begin{bmatrix}\n1&amp;0.75&amp;0.25\\\\\n0.75&amp;0.75&amp;0\\\\\n0.25&amp;0&amp;0.25\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;BKMKTTDWYO&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The weighted return vector is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X'Wy\n=\n\\begin{bmatrix}\n0.0425\\\\\n0.0250\\\\\n0.0175\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;JOATWJKCRH&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The first element is the weighted return contribution of the whole market:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.50(0.04)\n+\n0.25(0.02)\n+\n0.125(0.08)\n+\n0.125(0.06)\n=\n0.0425.&quot;,&quot;id&quot;:&quot;KAGYSICTZS&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The second is the weighted contribution from L1 assets:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.50(0.04)+0.25(0.02)=0.0250.&quot;,&quot;id&quot;:&quot;NQWXBXDXLQ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The third is the weighted contribution from Meme assets:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.125(0.08)+0.125(0.06)=0.0175.&quot;,&quot;id&quot;:&quot;VXBSHDOJIO&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The complete system is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{bmatrix}\n1&amp;0.75&amp;0.25&amp;0\\\\\n0.75&amp;0.75&amp;0&amp;0.75\\\\\n0.25&amp;0&amp;0.25&amp;0.25\\\\\n0&amp;0.75&amp;0.25&amp;0\n\\end{bmatrix}\n\\begin{bmatrix}\nf_{\\mathrm{market}}\\\\\nf_{\\mathrm{L1}}\\\\\nf_{\\mathrm{Meme}}\\\\\n\\lambda\n\\end{bmatrix}\n=\n\\begin{bmatrix}\n0.0425\\\\\n0.0250\\\\\n0.0175\\\\\n0\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;FLWUVWKMEA&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Solving gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{market}}\n=\n0.0425,&quot;,&quot;id&quot;:&quot;NCTNEISWPT&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{L1}}\n=\n-0.0091667,&quot;,&quot;id&quot;:&quot;TTFKTHVIBQ&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{Meme}}\n=\n0.0275.&quot;,&quot;id&quot;:&quot;FXPWBCQCTD&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The constraint is satisfied:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.75(-0.9167\\%)\n+\n0.25(2.75\\%)\n=\n0.&quot;,&quot;id&quot;:&quot;QGWGKMNPMP&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><h3>7. Interpretations</h3><p>The weighted return of the L1 category is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\overline r_{\\mathrm{L1}}\n=\n\\frac{\n0.50(4\\%)\n+\n0.25(2\\%)\n}{\n0.75\n}\n=\n3.3333\\%.&quot;,&quot;id&quot;:&quot;DUYTEQDWPG&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The weighted return of the Meme category is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\overline r_{\\mathrm{Meme}}\n=\n\\frac{\n0.125(8\\%)\n+\n0.125(6\\%)\n}{\n0.25\n}\n=\n7\\%.&quot;,&quot;id&quot;:&quot;YEMKHASMCR&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The category coefficients <em>are the differences between these category returns and the weighted market return:</em></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{L1}}\n=\n3.3333\\%-4.25\\%\n=\n-0.9167\\%,&quot;,&quot;id&quot;:&quot;NFNFTCNZGF&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{Meme}}\n=\n7\\%-4.25\\%\n=\n2.75\\%.&quot;,&quot;id&quot;:&quot;OYRTIUIBQS&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>The fitted common return for an L1 asset is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{\\mathrm{market}}+f_{\\mathrm{L1}}\n=\n4.25\\%-0.9167\\%\n=\n3.3333\\%.&quot;,&quot;id&quot;:&quot;ACXCYCQYSP&quot;}" data-component-name="LatexBlockToDOM"></div><p>The regression therefore tells us:</p><ul><li><p>the weighted market returned <em>4.25%</em>;</p></li><li><p>L1 underperformed the market by <em>0.9167%</em>;</p></li></ul><p>And the same exercise applies to the Memes category.</p><p>The residuals describe the returns not explained by category membership.</p><p>For BTC,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\epsilon_{\\mathrm{BTC}}\n=\n4\\%-3.3333\\%\n=\n0.6667\\%.&quot;,&quot;id&quot;:&quot;AAEOIHXCUM&quot;}" data-component-name="LatexBlockToDOM"></div><h3>8. Repeat the analysis through time</h3><p>The same cross-sectional regression is repeated for every date <em>t</em>. Each regression produces one market return and one relative return for every represented category:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\widehat f_t\n=\n\\begin{bmatrix}\n\\widehat f_{\\mathrm{market},t}\\\\\n\\widehat f_{\\mathrm{L1},t}\\\\\n\\widehat f_{\\mathrm{Meme},t}\\\\\n\\vdots\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;KUMNZJUUVL&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Stacking the daily estimates produces a synthetic return history for every category/sector.</p><p>For example,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\left\\{\nf_{\\mathrm{Meme},1},\nf_{\\mathrm{Meme},2},\n\\ldots,\nf_{\\mathrm{Meme},T}\n\\right\\}&quot;,&quot;id&quot;:&quot;WVIXURGZNJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>is the estimated history of the crypto meme-sector relative to the weighted crypto market. If we take these as &#8216;sector returns&#8217; and compound them from 1, we essentially have a synthetic sector index. This is (theoretically) tradable with a factor-mimicking portfolio.</p><h3>9. Recover the factor-mimicking weights</h3><p>The estimated coefficients are linear combinations of the asset returns. We may therefore recover asset weights that reproduce them exactly.</p><p>For the market factor, the mimicking weights are the normalised regression weights:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\mathrm{market}}\n=\n\\begin{bmatrix}\n0.50\\\\\n0.25\\\\\n0.125\\\\\n0.125\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;YFKKKQVZXY&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>For category <em>c</em>, the mimicking weights are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{c,i}\n=\n\\mathbf 1\\{i\\in c\\}\n\\frac{w_i}{s_c}\n-\nw_i.&quot;,&quot;id&quot;:&quot;EDMXMDVIJW&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>For L1, this gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\mathrm{L1}}\n=\n\\begin{bmatrix}\n0.50/0.75-0.50\\\\\n0.25/0.75-0.25\\\\\n-0.125\\\\\n-0.125\n\\end{bmatrix}\n=\n\\begin{bmatrix}\n0.1667\\\\\n0.0833\\\\\n-0.125\\\\\n-0.125\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;PPUXHRSCSM&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>These weights sum to zero:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;0.1667+0.0833-0.125-0.125=0.&quot;,&quot;id&quot;:&quot;BYBWDEDGYS&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Their realised return is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\mathrm{L1}}'y\n=\n0.1667(4\\%)\n+\n0.0833(2\\%)\n-\n0.125(8\\%)\n-\n0.125(6\\%)\n=\n-0.9167\\%.&quot;,&quot;id&quot;:&quot;JKPOGGSYST&quot;}" data-component-name="LatexBlockToDOM"></div><p>For Meme,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\mathrm{Meme}}\n=\n\\begin{bmatrix}\n-0.50\\\\\n-0.25\\\\\n0.125/0.25-0.125\\\\\n0.125/0.25-0.125\n\\end{bmatrix}\n=\n\\begin{bmatrix}\n-0.50\\\\\n-0.25\\\\\n0.375\\\\\n0.375\n\\end{bmatrix}.&quot;,&quot;id&quot;:&quot;AENOSNVHMW&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p>Its return is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{\\mathrm{Meme}}'y\n=\n-0.50(4\\%)\n-\n0.25(2\\%)\n+\n0.375(8\\%)\n+\n0.375(6\\%)\n=\n2.75\\%.&quot;,&quot;id&quot;:&quot;VLUDZKDEZZ&quot;}" data-component-name="LatexBlockToDOM"></div><p style="text-align: center;"></p><p><strong>This exactly reproduces the L1 factor return.</strong></p><p><strong>The category factor can therefore be interpreted as a long position in the weighted category basket and a short position in the weighted market basket.</strong></p><p><strong>The factor-mimicking portfolio exists exactly in the mathematics.</strong> Essentially, what we have done is to transform quantitative analysis from price space to factor space, using statistical categorical analysis. In the process, we might</p><ul><li><p>better appreciate crypto asset returns as a mixture of factors/sectors</p></li><li><p>construct a more informed portfolio by reducing noise in our samples</p></li></ul><p>For instance, using &#8220;theoretical&#8221; factor-mimicking portfolios, we may look to construct a long-short delta neutral portfolio for &#8220;bullish sectors&#8221; against &#8220;bearish sectors&#8221;. Or we may look to &#8220;enhance&#8221; our trend construction from the previous post to trading in the factor space, subject to same considerations of portfolio construction that were discussed.</p><h3>Code:</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y5iF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y5iF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 424w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 848w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 1272w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y5iF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png" width="728" height="264.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:529,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:607935,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206813161?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!y5iF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 424w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 848w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 1272w, https://substackcdn.com/image/fetch/$s_!y5iF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44d5b0fb-a147-469f-a887-136a94395538_3402x1236.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let&#8217;s take a look an example construction of the above test to a universe of hundred tickers from Binance and Python code.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-3df">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 1: trend my friend)]]></title><description><![CDATA[trend following over the years, with code]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-c9a</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-c9a</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Wed, 15 Jul 2026 12:48:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Y886!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><span>PSA: we have an </span><strong><span>ongoing, 1-week 50% discount on all subs.</span></strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3630dda0-7909-444c-add6-86f429d4528e&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Quantitative Trading Strategies - How I went from 10k to 100k to 1M (new series intro)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-07-13T15:27:14.056Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!XNBn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/quantitative-trading-strategies-how&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:206797572,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:16,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><span><br></span><strong><span>IN</span></strong><span> my first quant internship, I was tasked with testing commodity futures skew effects.<br><br></span><strong><span>pm:</span></strong><span> "how did you account for contract roll"<br><br></span><strong><span>me:</span></strong><span> "treated them as continuous, sometimes it's contango sometimes backwardated, so. it's small approximation error"</span></p><p><strong><span>pm: </span>&#128529;</strong></p><p>In trading, a lot of effects and strategies are known. Index rebalancing, stat arb, yield curve arbitrage, market making - are all known strategies. The devil is in the details, and like my old self, <em><strong>doing something and doing something right </strong></em><strong>are completely different things. If you are targeting these strategies, fantastic! You are in the right arena. For those testing some inverse shoulder rsi combo schtick, it&#8217;s time to come around. </strong>No shame in where the journey starts.</p><p>This article is dedicated a little bit to that - when asked about how one should &#8220;start their quant journey&#8221;, I always default to this one - a fantastically simple strategy that opens up a ton of critical questions that expand to more complex strategies. For example</p><ul><li><p>Execution fees and optimal rebalancing</p></li><li><p>Signal quantisation</p></li><li><p>Volatility and square root laws</p></li><li><p>Diversification</p></li><li><p>Backtesting sanitation</p></li><li><p>Signal transformation</p></li><li><p>Risk targeting/management</p></li><li><p>Order automation</p></li></ul><p>It is also one of the strategies that is &#8220;slow enough&#8221; that can be handled manually, and where different components mentioned above can be automated &#8220;one-at-a-time&#8221;, which is the good old principle of abstraction and core principle of building complex systems.<br></p><p>Our <em>next post</em> will continue on factor trading and how I leverage &#8216;smart-beta&#8217; strategies to enhance portfolio returns.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y886!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y886!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 424w, https://substackcdn.com/image/fetch/$s_!Y886!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 848w, https://substackcdn.com/image/fetch/$s_!Y886!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 1272w, https://substackcdn.com/image/fetch/$s_!Y886!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y886!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png" width="1456" height="399" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:399,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1003607,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206978369?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Y886!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 424w, https://substackcdn.com/image/fetch/$s_!Y886!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 848w, https://substackcdn.com/image/fetch/$s_!Y886!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 1272w, https://substackcdn.com/image/fetch/$s_!Y886!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244fa5f1-4c11-4691-8df0-b48ebfec32e2_3412x936.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Shall we begin? </p><p><strong>(Code is attached at the bottom.)</strong></p><h3>Signal is the easy part.</h3><p>The high-level rule is simple: buy markets that are going up and sell markets that are going down. It gives us a strategy whose intuition can be stated in one sentence, and then there is everything else.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{market data} \\rightarrow \\text{trend signal} \\rightarrow \\text{forecast} \\rightarrow \\text{position} \\rightarrow \\text{portfolio} &quot;,&quot;id&quot;:&quot;HEIUYLUVPV&quot;}" data-component-name="LatexBlockToDOM"></div><p>Until we specify how strongly to trade the signal, how much risk to allocate to each asset, how contracts are sized, when trades are executed and how costs are charged, it&#8217;s not a quantifiable test.</p><p>Trend following is therefore a useful first quantitative strategy for two reasons. It is simple enough that we can intuit the entire research process, while being rich enough to expose common lapses in framework and backtesting.</p><p>Moskowitz, Ooi and Pedersen document this effect across equity-index, currency, commodity and bond futures. A diversified portfolio of these signals produced returns with little exposure to conventional asset-pricing factors and <a href="https://w4.stern.nyu.edu/facdir/lpederse/papers/TimeSeriesMomentum.pdf">tended to perform well during large market moves</a>.</p><p>Let&#8217;s just say, there is a <em>ton</em> (two centuries) of evidence supporting trend following: <a href="https://research.cbs.dk/en/publications/a-century-of-evidence-on-trend-following-investing/">A Century of Evidence on Trend-Following Investing</a> and <a href="https://arxiv.org/abs/1404.3274">Two Centuries of Trend Following</a>.</p><p>As they say, if it&#8217;s robust, simple does the trick. The simplest discrete signal is the sign of a trailing return:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_{i,t}\n=\n\\operatorname{sign}\n\\left(\n\\frac{P_{i,t}}{P_{i,t-h}}-1\n\\right)&quot;,&quot;id&quot;:&quot;WIZXIVYRSA&quot;}" data-component-name="LatexBlockToDOM"></div><p>The forecast is +1 when the asset has appreciated over the previous <strong>h</strong> periods and -1 when it has depreciated.</p><p>A moving-average crossover produces a similar binary rule:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s_{i,t}\n=\n\\operatorname{sign}\n\\left(\nMA^{\\text{fast}}_{i,t}\n-\nMA^{\\text{slow}}_{i,t}\n\\right)&quot;,&quot;id&quot;:&quot;IGJOZDQOLV&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Now imagine if you were thirsty, and you could only drink or not drink a litre at a time. That would be miserable. A continuous forecast tries to retain information about trend strength. </p><p>A continuous forecast distinguishes between a weak and strong trend. It can also move gradually through zero rather than jumping directly from fully short to fully long. <a href="https://www.cmegroup.com/education/files/demystifiing-time-series-momentum-strategies.pdf">Continuous rules based on the statistical strength of a trend can materially reduce turnover without a statistically significant performance penalty</a>. </p><p>One possible construction is a volatility-normalised trailing return:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{i,t}\n=\n\\operatorname{clip}\n\\left(\n\\frac{\\sum_{k=1}^{h} r_{i,t-k}}\n     {\\hat{\\sigma}_{i,t}\\sqrt{h}},\n-f_{\\max},\nf_{\\max}\n\\right)&quot;,&quot;id&quot;:&quot;UBQOUAAANX&quot;}" data-component-name="LatexBlockToDOM"></div><p>In more nuance, weak trends appear to persist, but the relationship eventually saturates. We know this from the Potters and Bouchaud paper. The appropriate forecast may therefore look less like an infinitely increasing linear function and more like a clipped or saturating one. A sensible forecast transformation is often saturating:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\tilde f_{i,t}\n=\n\\tanh\\left(\\frac{f_{i,t}}{c}\\right)&quot;,&quot;id&quot;:&quot;NAOKCBZYTA&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Can I Have One HubbaHubba of Egg Contracts? On Risk.</h3><p>Said no-one ever. </p><p>Suppose Bitcoin and interest-rate futures both produce a forecast of +1. What does this even mean? Giving them the same dollar exposure makes no sense from an economic standpoint. A standard normalisation feature to encode a dimensionless forecast is the forecast annualised return volatility of asset <em>i:</em></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;u_{i,t}\n=\nb_i\n\\frac{f_{i,t}}{\\hat{\\sigma}_{i,t}}&quot;,&quot;id&quot;:&quot;KVKWXHEIBI&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>where <em>b_i</em> is an instrument or asset-class risk budget.</p><p>The inverse-volatility term gives smaller positions to volatile assets and larger positions to quiet assets. With binary forecasts and equal risk budgets, each <strong>instrument contributes approximately the same standalone volatility before correlations are considered.</strong></p><p>Extending this framework, asset normalisation does not guarantee portfolio risk stability. 10 contracts long A and 10 contracts short B is a different portfolio from 10 contracts long in each. Instruments are correlated, correlations are dynamic, and the positions are too.</p><p>Let <em>u_t</em> be the vector of preliminary exposures and let <em>Sigma</em> be the forecast covariance matrix of asset returns. The forecast volatility of the preliminary portfolio is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{\\sigma}_{p,t}\n=\n\\sqrt{u_t^\\top \\hat{\\Sigma}_t u_t}&quot;,&quot;id&quot;:&quot;MFHOGHBVWF&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Given a portfolio volatility target, the final exposure vector is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_t\n=\n\\frac{\\sigma^\\text{target}}\n     {\\hat{\\sigma}_{p,t}}\nu_t&quot;,&quot;id&quot;:&quot;HKKZFEZWPB&quot;}" data-component-name="LatexBlockToDOM"></div><p>scaling the whole portfolio so that its forecast volatility equals the target.</p><p>There are therefore two distinct pieces of risk management:</p><ol><li><p>Asset-level normalisation prevents volatile instruments from dominating the portfolio performance.</p></li><li><p>Portfolio-level scaling adjusts total leverage based on dynamic correlations and the realised volatility of the combined strategy in relation to target.</p></li></ol><p>Volatility targeting has a wider literature of its own. <a href="https://www.nber.org/papers/w22208">Reducing exposure during high-volatility periods improves the historical Sharpe ratios of several risk factors</a>. </p><h3>We Live in the Real World</h3><p>For a linear contract, a simplified conversion from notional weight to units is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;q_{i,t}\n=\n\\frac{A_t w_{i,t}}\n     {P_{i,t}M_iX_{i,t}}&quot;,&quot;id&quot;:&quot;CBGDYVEXMH&quot;}" data-component-name="LatexBlockToDOM"></div><p>where A is the portfolio capital, P is the contract price, M is contract multiplier and X is the currency conversion. The position must then respect integer contract quantities, minimum order sizes, tick sizes, leverage limits and venue-specific margin rules. This may surprise some crypto traders, but you can&#8217;t always buy 0.0001 of $MONKEY coin in liquid futures markets where standardised contracts trade in (large) fixed sizes. Accordingly, this tracking error can play a part in &#8216;which universe of assets&#8217; are sensibly tradable for hedge funds - even when AUM is minimally tens of millions! When generating backtests, we need to be careful about directionally correct and economically meaningless results.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_{p,t+1}\n=\nw_t^\\top r_{t+1}\n-\nC(\\Delta w_t)\n-\n\\operatorname{Carry}_{t+1}&quot;,&quot;id&quot;:&quot;GAZAWPXVTV&quot;}" data-component-name="LatexBlockToDOM"></div><p><br>Next on the chopping board of reality are fees. The cost function includes commissions, bid-ask spreads, slippage, market impact and carry/funding costs.  </p><p>Thankfully, when doing longer-term trend following, fees are more&#8230;secondary class citizens. However, as you evolve in your career as a trader, or look at higher frequency trading, you, too, will come to obsess about fees. But <strong>for now, </strong><em><strong>in this post,</strong> </em>we can be abit more cavalier about it.</p><p>To be frank, cost management and proper backtesting principles probably deserve an entire series on its own, but that borders on the HOW rather than the WHAT, and I promised not to bore you with the how in this series. I do have an entire post on <a href="https://quantpylib.hangukquant.com/learn/statistical_finance/#statistical-inferencing-for-quantitative-strategies">statistical inferencing for backtest validation</a>, if you are interested. </p><p>So, for now - <strong>COST IS IMPORTANT, and non-negligible, </strong>and ideas from optimal control theory suggest that we should&#8230;have continuous signals but not continuous positions. This prevents us from &#8220;flip-flopping&#8221; our holdings and paying the broker or the market maker excessively. Fortunately, we can get 95% of the way there with 5% of the brain: by applying &#8220;positional inertia&#8221; - the inertia to trade into target position when the current position is sufficiently close to the target.</p><p>The &#8220;rough-ideal&#8221; for inertia levels can be set by setting average trading costs and varying inertia levels, and then simply doing a walk forward backtest to find the optimal tradeoff. If robustness is anywhere found, a <em>reasonable band</em> will appear. Generally, the more noise (or low Sharpe your cost-free strategy is), the larger should be your inertia threshold. If your signal is all-noise, then you should just sit on your hands and stop trading all together.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R1m1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R1m1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R1m1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg" width="564" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:564,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R1m1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!R1m1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad33681-dc77-4a3c-9ad1-80b290d49ee3_564x500.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Code</h4><h4><strong>Comparing with and without costs:</strong></h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qycE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qycE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 424w, https://substackcdn.com/image/fetch/$s_!qycE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 848w, https://substackcdn.com/image/fetch/$s_!qycE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 1272w, https://substackcdn.com/image/fetch/$s_!qycE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qycE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp" width="1456" height="534" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:534,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34326,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206978369?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qycE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 424w, https://substackcdn.com/image/fetch/$s_!qycE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 848w, https://substackcdn.com/image/fetch/$s_!qycE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 1272w, https://substackcdn.com/image/fetch/$s_!qycE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bc2b36f-dca1-40cd-8e7a-53f520f7e915_1456x534.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>From a code perspective, it is critical from a research infrastructural standpoint to encompass all (or most) of the above concerns in a parsimonious framework. What separates novice traders from more sophisticated quantitative analysts is the research harness.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantitative-trading-strategies-how-c9a">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Quantitative Trading Strategies - How I went from 10k to 100k to 1M (new series intro)]]></title><description><![CDATA[uncovering some of the dirty work]]></description><link>https://www.research.hangukquant.com/p/quantitative-trading-strategies-how</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantitative-trading-strategies-how</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Mon, 13 Jul 2026 15:27:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XNBn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Not too long ago, I ran the nimble market-maker series, discussing important techniques for <strong>quants in pseudo-competitive</strong> trading environments.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e15247fb-9532-40bb-a044-aaef858d8517&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Nimble Market-Maker Alpha&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2025-11-19T17:21:12.345Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1734787101540-050257ab9ded?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMnx8ZHdhcmZ8ZW58MHx8fHwxNzYyMTkyMTczfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/nimble-market-maker-alpha&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:177905187,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:16,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>We developed a number of critical tips and tricks there that the quantitative trader should be aware of when profiling and deploying trading strategies. It was very well received, and a reader even changed their username to thenimblemm &#128517;</p><p></p><p>I&#8217;ve been writing this blog for 5 years now, and over the years - we focused mainly on developing quantitative <em>research frameworks</em> - on the <strong>how rather than the what</strong><em>. </em>Here and there, we discussed some quantitative <em>strategies, which talk about the what.</em></p><p><strong>After half a decade, I thought it would be a nice series to give some more detail into WHAT goes on behind the scenes in my &#8216;dirty operations&#8217;.</strong></p><p>From trend following, to factor trading, FX policy arbitrage, event driven trading, to cross-exchange statistical arbitrage and hft market making - these 5 years was a busy one!</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;816e252c-aef6-4fd5-9f0c-5982acf27aa2&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;2 Years, 1M PnL and Life as a Solo Crypto Quant&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-04-10T16:15:21.296Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Lvvp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/2-years-1m-pnl-and-life-as-a-solo&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:193809007,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:54,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h3>7 Days Discount</h3><p>For 1 week, all subscription plans are 50% off:</p><p><a href="https://www.research.hangukquant.com/d7b4564d">https://www.research.hangukquant.com/d7b4564d</a></p><p>You can also support me with a Lifetime Subscription here:</p><p><a href="https://buy.stripe.com/dRm3cw0mC05N6Am3XKe7m0f">https://buy.stripe.com/dRm3cw0mC05N6Am3XKe7m0f</a></p><p><br><strong>Shout out to the ~300 lifetime members who have supported me, love ya back.</strong></p><p><strong>Hope you look forward to the series!</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XNBn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XNBn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 424w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 848w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 1272w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XNBn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png" width="48" height="20.406593406593405" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:619,&quot;width&quot;:1456,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:96487,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206797572?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XNBn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 424w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 848w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 1272w, https://substackcdn.com/image/fetch/$s_!XNBn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3385a8ef-4ad1-44bf-b1cd-72a423fd5984_1728x735.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p>]]></content:encoded></item><item><title><![CDATA[Manage Your Quantitative Tick Data Lake with Quantpylib]]></title><description><![CDATA[Mathematics, Finance and Their Babies. 
quant research and quant dev.]]></description><link>https://www.research.hangukquant.com/p/manage-your-quantitative-tick-data</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/manage-your-quantitative-tick-data</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Wed, 08 Jul 2026 18:13:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EsF3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last post, we discussed what institutional data capture needs to preserve and how to design a clean architecture for maintaining your own data lake for quantitative research.</p><p>This is available in quantpylib, our quant repo for annual, paid subscribers:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c08cb5e7-045f-4abb-bf54-66c9becbb158&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;HangukQuant quantpylib Github Repo&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2023-11-24T16:59:27.729Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/hangukquant-community-github-repo&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:139132009,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:29,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>We have <strong>redesigned critical core architecture and subsystems that will enable powerful workflows for traders using quantpylib</strong> in their trading infrastructure. Examples include performant and institutional-grade data replay, event journaling, telemetry systems and quantitative analytics.</p><p>We are proud to announce that managing your data lake has been now made a ~100~ lines of code powered by quantpylib, into raw binary flat files.</p><p>We have also shipped and documented a bunch of improvements to our backend, including cpp implementations for native orderbooks states. Once we launch versioning, we will deprecate old APIs.</p><p>See our data archival example here:</p><p><a href="https://quantpylib.hangukquant.com/hft/hft/#data-archival">https://quantpylib.hangukquant.com/hft/hft/#data-archival</a></p><p>See our feed model and QBN encoding notes:</p><p><a href="https://quantpylib.hangukquant.com/hft/feed/">https://quantpylib.hangukquant.com/hft/feed/</a></p><p><a href="https://quantpylib.hangukquant.com/hft/l0/">https://quantpylib.hangukquant.com/hft/l0/</a></p><p>Our new, performant native orderbook implementation is documented here:<br><a href="https://quantpylib.hangukquant.com/hft/orderbook/">https://quantpylib.hangukquant.com/hft/orderbook/</a><br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EsF3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EsF3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 424w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 848w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EsF3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png" width="1456" height="1283" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1283,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1868483,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/206133789?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EsF3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 424w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 848w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 1272w, https://substackcdn.com/image/fetch/$s_!EsF3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b55722f-9904-41e9-90b2-f389db65ee22_2150x1894.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We continue our aim of providing institutional grade trading infrastructure available to serious traders.</p><h5>Note:<br>We intend to increase quantpylib&#8217;s costs over the coming weeks with a change in access model. Existing users with access will see no change. Non-subscribers may obtain an access pass <a href="https://quantpylib.hangukquant.com/pricing/pricing/">here</a>.</h5><p></p>]]></content:encoded></item><item><title><![CDATA[Designing Institutional Data Capture for Quantitative Research.]]></title><description><![CDATA[Payload to Disk.]]></description><link>https://www.research.hangukquant.com/p/designing-institutional-data-capture</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/designing-institutional-data-capture</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 03 Jul 2026 13:17:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IRvk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello folks, I&#8217;ve spent the couple of months working on quantpylib, and the bulk of the refactor has been done~ I am excited to start doing up the docs so our users can experiment with it. <strong>As early as next week!</strong></p><p>One of the revamped subsystems was the improvement of data capture architecture towards more institutional grade archival policies. This article will be dedicated to describing what may constitute such a change.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IRvk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IRvk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 424w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 848w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 1272w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IRvk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png" width="663" height="363.83035714285717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:799,&quot;width&quot;:1456,&quot;resizeWidth&quot;:663,&quot;bytes&quot;:1611185,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/204803981?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IRvk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 424w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 848w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 1272w, https://substackcdn.com/image/fetch/$s_!IRvk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da95310-88bf-4654-8ff1-9732597a1bf2_1693x929.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Modern quantitative research</strong> is becoming less constrained by storage cost and more constrained by the quality of the artefacts we choose to preserve. Cheap cloud object stores, high-throughput local disks, and increasingly capable agents have changed the economics of retention. It is now <em>cheaper to store, easier to dig, </em><strong>making</strong><em><strong> </strong></em><strong>data storage policies and approach correctness a step-change more important as an interface for humans and intelligent solutions to sift through valuable insights hidden in the data.</strong></p><p>For a trading desk, the highest-value artefacts are the operational record: market data, order traces, fills, gateway logs, replay journals, risk decisions, and the metadata that ties these streams together. Agents are good at sifting, ranking, joining, and summarising. But they are only as useful as the substrate underneath them.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/designing-institutional-data-capture">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Designing L2 and L3 Orderbook (without Templates)]]></title><description><![CDATA[with Mechanical and Situational Empathy]]></description><link>https://www.research.hangukquant.com/p/designing-l2-and-l3-orderbook-without</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/designing-l2-and-l3-orderbook-without</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Wed, 10 Jun 2026 17:17:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/sX2nF1fW7kI" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello folks, it&#8217;s been awhile. I&#8217;ve spent the last 2+ weeks working day-day on the quantpylib library. A handful of folks have requested access recently, and I have not yet updated the docs, simply because our dev speed is too rapid atm and it would be futile to keep it updated. Forgive me for that.<br>Previously, we <strong>introduced a new state of the art logging subsystem:</strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;812af068-652c-4f3f-a3d2-667c51653491&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Designing State-of-the-Art Logging in Python&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-05-08T12:55:55.553Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!NdZd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/designing-state-of-the-art-logging&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:196889438,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:13,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><br>And as of late, we have <strong>completely revamped the archival subsystem (to a custom L0 binary capture),</strong> and am in the process of rewriting the native orderbooks, as well as data replay systems. I am also working on a sidecar terminal application so that traders/market makers with strategies powered by quantpylib have institutional grade trading infrastructure backing them.</p><p>Anyhow, since I was on the topic, today, we are going to do a light(er) article on implementing an orderbook. Previously, we already spoke on this topic:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;10056097-7741-4535-baca-e5a3a75b74ef&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Implementing a C-level Orderbook in Python&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2025-03-14T17:57:26.147Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F656511ba-42cb-4ddc-8274-26db66aeb882_1000x500.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/implementing-a-c-level-orderbook&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:159076270,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:8,&quot;comment_count&quot;:4,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>While that was a pretty simple and intuitive discussion, much more detail can be assigned to this task. It is also a common question at quant dev interviews, and I have recently had quant friends drilled on these.</p><p>Extending from our previous discussion, if we would like to extend an orderbook implementation into something matching-engine compatible and full-depth, the book needs to support queue position. That means the interface is no longer only MBP (market by price), but rather an MBO surface (market by order). </p><p>When it comes to L3 implementation, there are roughly two schools of thought. The standard text of reference is David Gross&#8217;s CppCon talk, <em>When Nanoseconds Matter: Ultrafast Trading Systems in C++</em>.</p><div id="youtube2-sX2nF1fW7kI" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;sX2nF1fW7kI&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/sX2nF1fW7kI?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Some of the design pressures in this post are motivated by that discussion. Here we will provide some clarity and implementation on Gross&#8217;s solution and also expand on the crypto&#8217;s common L2 domain, and how we can support both interface efficiently without template overhead.</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/designing-l2-and-l3-orderbook-without">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Quantpylib Polymarket v2 Integration]]></title><description><![CDATA[quantpylib vendors the most intuitive and efficient Python integration for Polymarket.]]></description><link>https://www.research.hangukquant.com/p/quantpylib-polymarket-v2-integration</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantpylib-polymarket-v2-integration</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Thu, 21 May 2026 09:13:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ks5b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346828f-679d-4ed3-802b-cce48511765e_2606x1556.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><a href="https://quantpylib.hangukquant.com/wrappers/polymarket/">quantpylib</a></strong> vendors Polymarket&#8217;s CLOB V2 migration to new exchange contracts, pUSD collateral, V2 EIP-712 and ERC-1271 signing.</p><p>As a market maker with more than 100m+ of volume and leading PnL on the platform, the optimizations I&#8217;ve made to the SDK is now available to all quantpylib users. Websocket integration is also complete.</p><p>The optimizations include:</p>
      <p>
          <a href="https://www.research.hangukquant.com/p/quantpylib-polymarket-v2-integration">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Designing State-of-the-Art Logging in Python]]></title><description><![CDATA[bringing nanosecond-level logging to Python and techniques applied]]></description><link>https://www.research.hangukquant.com/p/designing-state-of-the-art-logging</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/designing-state-of-the-art-logging</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 08 May 2026 12:55:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NdZd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello friends~</p><p>This post, we will discuss the <strong>introduction of a state of the art performance Python logging subsystem in quantpylib</strong>, and discuss some of the key design principles that allow us to achieve this. To my knowledge, among all Python logging frameworks, it is the lowest latency implementation out there.</p><p>As an aside, I am focused on making quantpylib into a more mature platform for serious quants. Beyond my expectations, the repo has found its way into many retail traders&#8217; workflow, and even some small institutional trading stacks. </p><p>The project, although originally intended to be &#8216;my personal infra&#8217; - is now bigger than myself, and accordingly, we will look to adopt higher standards appropriate to the gravity of its use cases. Although it is a best-effort guarantee service, the best-est of the effort will be brought forth.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c7ed27a3-aba2-4c57-8ecc-33adc404f142&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;HangukQuant quantpylib Github Repo&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2023-11-24T16:59:27.729Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/hangukquant-community-github-repo&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:139132009,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:29,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Let&#8217;s get started!</p><p>A taster: (<strong>on log scale)</strong>, quantpylib&#8217;s logger is 30-70x faster than standard <em>logging</em> and microsoft&#8217;s <em>picologging</em> library!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NdZd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NdZd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 424w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 848w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 1272w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NdZd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png" width="1456" height="542" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:542,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:582887,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/196889438?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NdZd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 424w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 848w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 1272w, https://substackcdn.com/image/fetch/$s_!NdZd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40d93e98-9675-4d08-aecc-318e4e4a626b_1682x626.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong><br>Logging</strong> is an important part of system observability. It gives us a way to reconstruct the system states, what decisions it made, and where things failed in live systems.</p><p>However, logging is not free. A log invocation may require caller discovery, record construction, string formatting, structured field handling, handler traversal, locks, stream writes, flush behavior, and sometimes exception or stack formatting. In latency-sensitive tasks such as trading, this cost can sit directly in the hot path.</p><p>In Python, reducing this cost is difficult because the usual logging path is intentionally dynamic. Python objects are allocated, frames may be inspected, dictionaries are populated, handlers own locks, and formatting often happens before the caller can move on. This is not the shape we want for threads parsing market data and executing time-sensitive actions.</p><p>To alleviate these issues, a number of existing libraries try to improve different parts of the logging problem. A couple examples - </p><ul><li><p><em>picologging</em> is designed as a faster, mostly drop-in replacement for the standard library logging module. This is useful if the main constraint is compatibility with the existing logging API, while moving parts of the implementation into faster native (C) code.</p></li><li><p><em>loguru</em> attacks a slightly different problem. It makes logging much easier to configure and use: sinks, serialization, contextual binding, lazy formatting, and nicer ergonomics. Its <em>lazy=True</em> path can defer evaluation of expensive arguments until the message is actually emitted. Emitted log still travels through Loguru's event construction, formatting, and sink pipeline.</p></li></ul><p>Although these are good libraries, most of them still preserve the broad log-record shape: create an event-like record, attach metadata, decide when the message is constructed, and push the result through a sink. </p><p>They differ in how much work is deferred and whether message construction happens directly in the hot path, but the core abstraction is still a dynamic log record carrying metadata through a logging pipeline. <strong>The end result is that log invocations cost up to microseconds</strong>. Where we are targeting t2t in the microsecond teens and below, observability is a hefty price to pay.</p><p>Our objective, therefore, is to be able to generate structured, useful logging in Python applications - that can be aggregated and analysed downstream in logging pipeline(s) such as as for ingestion into a Loki database.</p><p>In order to target this objective, we would like to ask ourselves the following questions:</p><ul><li><p>what components of log invocation add to the hot path?</p></li><li><p>how do we reduce the number of Python object allocations in that path?</p></li><li><p>which part of the logging workflow is actually costly: call-site lookup, record construction, argument formatting, handler traversal, serialization, or I/O?</p></li><li><p>do we walk the Python frame stack to recover metadata such as filename, pathname, function name, or line number, and if so, how often?</p></li><li><p>what concurrency mechanism makes logging thread-safe?</p></li><li><p>if the logger acquires a lock, where is that lock acquired and how expensive is it under contention?</p></li><li><p>does the caller thread format strings, or can formatting be deferred?</p></li><li><p>does the caller thread call into the kernel for file or stream writes, or is that pushed into a writer thread?</p></li><li><p>is the path synchronous with the sink, or does the caller only publish a compact record and move on?</p></li></ul><h3>Standard Path</h3><p>A normal call like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;de0847ca-9ac5-407b-bd6d-d616fb6427a5&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">logger.info(&#8221;fill %d @ %f for %s&#8221;, qty, px, symbol)</code></pre></div><p>can involve a surprisingly long sequence of work:</p><ol><li><p><strong>Enabled-level check:</strong> the logger has to decide whether the event is filtered out by the logger level, handler level, or effective inherited level.</p></li><li><p><strong>Caller discovery / frame inspection:</strong> the logger may inspect Python frames to recover metadata such as filename, pathname, function name, and line number.</p></li><li><p><strong>LogRecord construction:</strong> the logger creates a Python object representing the event.</p></li><li><p><strong>Attribute population:</strong> the record is filled with message arguments, timestamps, process/thread metadata, exception information, stack data, and user-provided extra fields.</p></li><li><p><strong>Handler traversal:</strong> Python logging is hierarchical, so the event may walk through logger and parent-handler control flow depending on propagation settings.</p></li><li><p><strong>Filters:</strong> each logger or handler may run user-defined filters before the record is emitted.</p></li><li><p><strong>Locks:</strong> handlers need synchronization because multiple threads may write into the same logging sink.</p></li><li><p><strong>Formatting:</strong> the message string, structured fields, timestamp, exception text, or JSON representation are constructed.</p></li><li><p><strong>Stream writes and flush behavior:</strong> the final bytes are written to stdout, a file, socket, or another sink, possibly crossing into the kernel or blocking on I/O.</p></li></ol><p>The logging libraries including the ones we mentioned improve parts of this path, but many still operate in the same conceptual shape: create an event object, attach dynamic fields, render it, and pass it through a logging pipeline.</p><p>To break this latency floor, we have to remove pieces of the constraint rather than merely make each piece a little faster. The useful observation is that most log invocation sites are only partially dynamic.</p><p>For example, in printf-style logging invocations, the static information usually includes the format string, file name, line number, severity, number of arguments, and rough parameter types. The dynamic information is much smaller: the values passed into that invocation, occasional <em>extra</em> fields, and the timestamp.</p><p>These points carry forward into the implementation&#8217;s optimization techniques.</p><h3>Techniques</h3><p>For the specific implementation, refer to the <em>quantpylib</em> codebase. The high-level design is easier to discuss in terms of the techniques applied.</p><h3><strong>static information registry</strong></h3><p>The first technique is to treat a log invocation site as something that can be registered once and then referred to cheaply.</p><p>The Python-facing fast path resolves the caller into a key based on the CPython code object and line number. Implementation-wise, this goes through CPython frame objects: get the current frame, recover the <em>PyCodeObject</em>, read the line number, and combine the code-object pointer and line number through a small custom hash. The result is a per-thread cache key for that call site.</p><p>On a cache hit, the logger gets back a stable integer id. On a cache miss, the format string and frame metadata are registered into a static registry: pathname, filename, line number, severity, parameter count, rough parameter types, and an unload/formatting function. This id uniquely identifies the log invocation site.</p><p>Instead of constructing a fresh record that contains all metadata, each emitted record can contain a pointer to the static data plus only the dynamic payload:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;7d5ae96f-23f2-4f3d-841d-fd4e6511f69e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">struct StaticData {
  const char* pathname;
  const char* filename;
  const char* format;
  uint32_t line_number;
  LogLevel severity;
  int num_params;
  const ParamType* param_types;
  UnloadFn unloadfn;
};

struct LogEntry {
  const StaticData* static_data_ptr;
  uint64_t timestamp;
  uint16_t entry_size;
  uint8_t reserved[6];
  char args[];
};</code></pre></div><p>There is a deliberate Python-specific constraint here that we enforce, which is that format strings should be stable literals.</p><p>For example, the intended shape:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;b352d07f-76e0-4e98-a549-fcd7bc2f3739&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">log.info("fill %d @ %f for %s", qty, price, symbol)</code></pre></div><p>is remarkably distinct from </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;5f6ebae8-93d6-420b-b865-af38b699b435&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">log.info(f"fill {qty} @ {price} for {symbol}")</code></pre></div><p>In the first case, the format string is a literal object associated with the call site.  In CPython, the compiled code object holds constants in its constant table, and repeated execution of that call site loads the same Python string object from that table. Object identity is represented by the object&#8217;s address for its lifetime, i.e. what <em>id(obj)</em> exposes at the Python level. The logger uses this idea at the native layer by recording the PyObject* pointer for the format string. For repeated invocations of the same literal-style call site, that pointer remains stable.</p><p>In the second case, Python constructs a new string value dynamically, so the format string&#8217;s address is no longer a stable part of the call-site key. If the same source line starts producing different string objects, the logger cannot safely say that the cached id still refers to the same static logging schema, so it rejects the call.</p><p>This is a limitation we enforce so that the call-site cache is meaningful.</p><h3><strong>transportation layer</strong></h3><p>After the call-site cache resolves the static metadata id, the next problem is transportation: how do we move the dynamic log payload across the producer/writer thread boundary without turning the log invocation into a normal synchronized I/O operation?</p><p>The backend borrows from the LMAX Disruptor design. The important optimizations in that family of designs are as follows:</p><ol><li><p>Preallocation: allocate the ring buffer upfront so memory can be reused instead of dynamically allocated on every log invocation.</p></li><li><p>Lock-free producer hot path: producers writing to the ring buffer avoid a lock/mutex on the latency-sensitive path, which removes the handler-lock shape of conventional logging.</p></li><li><p>Sequence caching: the producer memoizes the observed consumer sequence, amortizing the core-to-core cache-coherence traffic that would otherwise come from producer/consumer progress tracking.</p></li></ol><p>Additionally, beyond the algorithmic improvements, the transportation layer makes optimizations designed to run well on modern hardware architectures:</p><ol start="4"><li><p>Cache-line aware sequence counters: sequence counters are aligned and padded to cache-line boundaries to reduce false sharing.</p></li><li><p>Power-of-two indexing: ring positions can be computed with a bit mask instead of modulo arithmetic.</p></li></ol><p>We generalize the LMAX Disruptor idea from a ring of fixed event objects to a ring over raw byte buffers.</p><p>The producer and the writer/consumer agree on a raw byte encoding for log entries. Instead of communicating Python objects or fixed event slots, the producer writes log entries as contiguous bytes using this encoding scheme, and the writer later decodes the bytes into formatted output. This matters because log records are not naturally fixed-size. A no-argument message, a three-argument printf-style message, and a message with dynamic extra fields have different byte footprints. Instead of forcing them into a fixed slot size, the logger reserves the exact number of bytes required for:</p><ul><li><p>the LogEntry header;</p></li><li><p>the pointer to static metadata;</p></li><li><p>timestamp and entry size;</p></li><li><p>packed printf-style arguments;</p></li><li><p>other fixed and variable length fields.</p></li></ul><p>Each producing thread owns a thread-local log buffer. Conceptually, this turns the logging transport into multiple SPSC-style queues: each producer publishes into its own buffer, and the writer side consumes from those buffers. This reduces producer-side contention because producers are not fighting over the same write sequence.</p><p>The writer thread (in a non critical path) is then responsible for merging log entries from the thread-local buffers. In the implementation, this is done with an appropriate ordering structure such as a priority heap over timestamps. The writer side also decides where the log output should go, when writes should be flushed, and what policy should govern the generation of the actual log lines.</p><p>Further, the writer side can be pinned to a housekeeping core and can perform the heavier work of turning byte records into the desired output format, such as JSON or K=V logs. This not only defers formatting and heavy I/O away from the hot path, but also helps keep the producer working set smaller and friendlier to L1/L2 cache behavior, which matters on modern architectures.</p><h3>Benchmark</h3><p>Based on the techniques, here are the benchmarks, and the benchmarking code: (note that exceptions call Python runtime&#8217;s stack trace formatting/utilities before calling into the logger framework)</p><h4>File Sink</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2uD4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2uD4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 424w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 848w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 1272w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2uD4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png" width="1456" height="854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:854,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2311315,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/196889438?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2uD4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 424w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 848w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 1272w, https://substackcdn.com/image/fetch/$s_!2uD4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61dfad46-2e1d-42ee-9360-e1a1843155e2_3456x2028.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a41c4dae-e7ea-4f4c-b288-057fdf8a6ebc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">=========== sink=file ===========

--- file / no_args ---
variant                   p50        p90        p99          max
stdlib                  6417n      7834n     15000n      129125n
loguru                 14792n     16796n     25750n     1213250n
picologging             5375n      6875n     13293n      110333n
structlog               3917n      4458n      8500n     1334334n
quantpylib-perf          167n       208n       375n       56708n

--- file / 1xint ---
variant                   p50        p90        p99          max
stdlib                  6667n      8500n     15418n      127875n
loguru                 15125n     18042n     29792n      706875n
picologging             5458n      7500n     13667n      131833n
structlog               4542n      4958n     10918n      108833n
quantpylib-perf          167n       208n       292n       10417n

--- file / 3xmixed ---
variant                   p50        p90        p99          max
stdlib                  6625n      7838n     14376n      114458n
loguru                 14875n     15542n     21250n     1903917n
picologging             5500n      5833n     11042n      124791n
structlog               4584n      4792n      8458n       28208n
quantpylib-perf          167n       209n       375n        1208n

--- file / extra ---
variant                   p50        p90        p99          max
stdlib                  7417n      8087n     14501n       29000n
loguru                 15791n     16417n     22000n     1438458n
picologging             5625n      6834n     12583n      112959n
structlog               4542n      4709n      6875n       26708n
quantpylib-perf          292n       334n       750n        1916n

--- file / exception ---
variant                   p50        p90        p99          max
stdlib                 37375n     44834n     68668n     1062792n
loguru                 49083n     60042n     97542n     3616500n
picologging            29458n     32458n     50125n      233792n
structlog              30416n     32167n     40626n     1301708n
quantpylib-perf        22834n     23459n     32667n       78333n

--- file / filtered ---
variant                   p50        p90        p99          max
stdlib                   125n       125n       375n        9083n
loguru                   459n       583n      1500n       24000n
picologging               42n        84n       334n       19958n
structlog               1042n      1084n      1458n       14458n
quantpylib-perf           42n        83n       167n       23667n</code></pre></div><h4>Stdout Sink</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0zzj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0zzj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 424w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 848w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 1272w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0zzj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png" width="1456" height="854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:854,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3714513,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/196889438?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0zzj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 424w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 848w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 1272w, https://substackcdn.com/image/fetch/$s_!0zzj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6411ef0-4364-41f4-b794-923ea8835c28_3456x2028.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ddde7393-b224-4e9a-8d46-bf2350b548fb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">--- stdout / no_args ---
variant                   p50        p90        p99          max
stdlib                 11000n     13167n     37167n      553916n
loguru                 23833n     28083n    499468n     4076250n
picologging             9167n     10583n     20500n    56333375n
structlog               6083n      8625n     15459n      356625n
quantpylib-perf          167n       500n      1250n       34167n

--- stdout / 1xint ---
variant                   p50        p90        p99          max
stdlib                 11209n     13042n     23877n      197000n
loguru                 23833n     27541n    498848n     5344250n
picologging             8750n     10213n     14792n      212500n
structlog               6709n      8667n     13375n      109334n
quantpylib-perf          167n       542n      1041n       14333n

--- stdout / 3xmixed ---
variant                   p50        p90        p99          max
stdlib                 10959n     12750n     19750n      250958n
loguru                 24250n     29379n    530761n     3686250n
picologging             8958n     10458n     17375n      180542n
structlog               7250n      9042n     18668n      159709n
quantpylib-perf          208n       416n       709n       16166n

--- stdout / extra ---
variant                   p50        p90        p99          max
stdlib                 12958n     15084n     42048n      573750n
loguru                 25583n     29708n    527216n     3164916n
picologging             9042n     10542n     17590n      190875n
structlog               7917n      9625n     17209n       88417n
quantpylib-perf          292n       708n      1208n       40584n

--- stdout / exception ---
variant                   p50        p90        p99          max
stdlib                 68917n     89379n    553959n     3580625n
loguru                 83875n    109721n    816045n     6636292n
picologging            46125n     51625n     66709n     1413083n
structlog              63375n     82712n    591252n     3555583n
quantpylib-perf        24083n     39379n     63922n     1239959n

--- stdout / filtered ---
variant                   p50        p90        p99          max
stdlib                   125n       167n       541n       13500n
loguru                   500n       542n      1125n      119708n
picologging               42n        84n       125n        1042n
structlog               1167n      1625n      9542n      671791n
quantpylib-perf           42n       167n       334n        5292n</code></pre></div><p><strong>Bench Code:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;b490f35e-6c29-448c-a74b-5a81a09df8a4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import os
import sys
import time
import logging
from pathlib import Path

import numpy as np
import matplotlib.pyplot as plt
import quantpylib.logger as qlogger

LOG_FILE = "bench.log"
ITERS = 10_000
PAUSE_MICROS = 10

WORKLOADS = [
    "no_args",
    "1xint",
    "3xmixed",
    "extra",
    "exception",
    "filtered",
]
SINKS = ["file", "stdout"]

def invocations(fn, iters, pause_micros):
    fn() #warmup
    latencies = []
    for _ in range(iters):
        t0 = time.perf_counter_ns()
        fn()
        latencies.append(time.perf_counter_ns() - t0)
        if pause_micros:
            time.sleep(pause_micros / 1_000_000)
    return latencies

void_log = lambda logger: lambda : logger.info("hello")
int_log = lambda logger: lambda : logger.info("x=%d", 42)
mixed_log = lambda logger: lambda : logger.info("fill %d @ %f for %s", 42, 3.14, "btc")
extra_log = lambda logger: lambda : logger.info(
    "fill %d @ %f for %s",
    42,
    3.14,
    "btc",
    extra={"venue": "binance", "tag": "maker", "oid": 1234},
)
filtered_log = lambda logger: lambda : logger.debug("x=%d", 42)

def exception_log(logger):
    def log():
        try:
            1 / 0
        except Exception:
            logger.error(
                "error",
                extra={"exc": qlogger.get_exception(), "stack": qlogger.get_stack()},
            )
    return log

def bench_workloads(logger, iters=ITERS, pause_micros=PAUSE_MICROS):
    return {
        "no_args": invocations(void_log(logger), iters, pause_micros),
        "1xint": invocations(int_log(logger), iters, pause_micros),
        "3xmixed": invocations(mixed_log(logger), iters, pause_micros),
        "extra": invocations(extra_log(logger), iters, pause_micros),
        "exception": invocations(exception_log(logger), iters, pause_micros),
        "filtered": invocations(filtered_log(logger), iters, pause_micros),
    }

def _attach_handler(log, sink, handler_factory):
    for h in list(log.handlers):
        log.removeHandler(h)
    handler = handler_factory(sink)
    log.addHandler(handler)
    log.propagate = False

class LoguruAdapter:
    def __init__(self, logger):
        self._logger = logger

    def debug(self, msg, *args, extra=None):
        self._log("DEBUG", msg, args, extra)

    def info(self, msg, *args, extra=None):
        self._log("INFO", msg, args, extra)

    def error(self, msg, *args, extra=None):
        self._log("ERROR", msg, args, extra)

    def _log(self, level, msg, args, extra):
        logger = self._logger.bind(**extra) if extra else self._logger
        logger.opt(lazy=True).log(level, "{}", lambda: msg % args if args else msg)

class StructlogAdapter:
    def __init__(self, logger):
        self._logger = logger

    def debug(self, msg, *args, extra=None):
        self._log("debug", msg, args, extra)

    def info(self, msg, *args, extra=None):
        self._log("info", msg, args, extra)

    def error(self, msg, *args, extra=None):
        self._log("error", msg, args, extra)

    def _log(self, method, msg, args, extra):
        event = msg % args if args else msg
        kwargs = extra if extra else {}
        getattr(self._logger, method)(event, **kwargs)

def bench_stdlib(sink, log_file, **workload_kwargs):
    log = logging.getLogger("stdlib")
    log.setLevel(logging.INFO)
    def factory(sk):
        h = logging.FileHandler(log_file, mode='a') if sk == "file" else logging.StreamHandler()
        h.setLevel(logging.INFO)
        h.setFormatter(qlogger.JSONFormatter())
        return h
    _attach_handler(log, sink, factory)
    return bench_workloads(log, **workload_kwargs)

def bench_loguru(sink, log_file, **workload_kwargs):
    from loguru import logger
    logger.remove()
    output = log_file if sink == "file" else sys.stdout
    logger.add(output, level="INFO", serialize=True, enqueue=False)
    return bench_workloads(LoguruAdapter(logger), **workload_kwargs)

def bench_picologging(sink, log_file, **workload_kwargs):
    import picologging
    log = picologging.getLogger("picologging")
    log.setLevel(picologging.INFO)
    def factory(sk):
        h = picologging.FileHandler(log_file, mode='a') if sk == "file" else picologging.StreamHandler()
        h.setLevel(picologging.INFO)
        h.setFormatter(qlogger.JSONFormatter())
        return h
    _attach_handler(log, sink, factory)
    return bench_workloads(log, **workload_kwargs)

def bench_structlog(sink, log_file, **workload_kwargs):
    import structlog
    output = open(log_file, "a") if sink == "file" else sys.stdout
    structlog.configure(
        processors=[
            structlog.processors.add_log_level,
            structlog.processors.JSONRenderer(),
        ],
        wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
        logger_factory=structlog.WriteLoggerFactory(file=output),
        cache_logger_on_first_use=False,
    )
    try:
        return bench_workloads(StructlogAdapter(structlog.get_logger("structlog")), **workload_kwargs)
    finally:
        if sink == "file":
            output.close()

def bench_pylogger(sink, log_file, **workload_kwargs):
    from quantpylib.logger.logger import Logger
    log_path = Path(log_file)
    log = Logger(
        name=sink,
        register_handlers=[],
        stdout_register=(sink == "stdout"),
        stdout_level=logging.INFO,
        file_register=(sink == "file"),
        filename=log_path.name,
        logs_dir=str(log_path.parent or Path(".")),
        file_level=logging.INFO,
    )
    return bench_workloads(log, **workload_kwargs)

def bench_cplogger(sink, log_file, **workload_kwargs):
    from quantpylib.logger import Logger
    log_path = Path(log_file)
    log = Logger(
        # name="perf", defaults to perf
        stdout_register=(sink == "stdout"),
        stdout_level=logging.INFO,
        stdout_formatter_cls=qlogger.JSONFormatter,
        file_register=(sink == "file"),
        filename=log_path.name,
        logs_dir=str(log_path.parent or Path(".")),
        file_level=logging.INFO,
        file_formatter_cls=qlogger.JSONFormatter,
    )
    results = bench_workloads(log, **workload_kwargs)
    return results

def print_table(workload, results, sink):
    print(f"\n--- {sink} / {workload} ---")
    print(f"{'variant':&lt;18} {'p50':&gt;10} {'p90':&gt;10} {'p99':&gt;10} {'max':&gt;12}")
    for variant, data in results.items():
        lats = np.asarray(data[workload])
        print(f"{variant:&lt;18} {np.percentile(lats, 50):&gt;9.0f}n {np.percentile(lats, 90):&gt;9.0f}n {np.percentile(lats, 99):&gt;9.0f}n {np.max(lats):&gt;11.0f}n")

def plot_sink(sink, results):
    cols = 2
    rows = int(np.ceil(len(WORKLOADS) / cols))
    fig, axes = plt.subplots(rows, cols, figsize=(12, 4 * rows))
    for ax, w in zip(axes.flat, WORKLOADS):
        for variant, data in results.items():
            ax.plot(data[w], label=variant, alpha=0.6)
        ax.set_title(w)
        ax.set_xlabel('Iteration')
        ax.set_ylabel('Time (ns)')
        ax.set_yscale('log')
        ax.legend()
    for ax in axes.flat[len(WORKLOADS):]:
        ax.set_visible(False)
    fig.suptitle(f'logger latency: sink={sink}')
    fig.tight_layout()

def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('-sink', '--sink', type=str, help='Specify logging sink = [file, stdout]', choices=SINKS, default='file')
    parser.add_argument("--log-file", type=str, default=LOG_FILE)
    parser.add_argument("--iters", type=int, default=ITERS)
    parser.add_argument("--plot", action=argparse.BooleanOptionalAction, default=True)
    args = parser.parse_args()
    sink = args.sink
    
    if os.path.exists(args.log_file):
        os.remove(args.log_file)

    all_results = {}
    print(f"\n=========== sink={sink} ===========")
    variants = {
        "stdlib": bench_stdlib(sink, args.log_file, iters=args.iters),
        "loguru": bench_loguru(sink, args.log_file, iters=args.iters),
        # "quantpylib-root": bench_pylogger(sink, args.log_file, iters=args.iters),
        "picologging": bench_picologging(sink, args.log_file, iters=args.iters),
        "structlog": bench_structlog(sink, args.log_file, iters=args.iters),
        "quantpylib-perf": bench_cplogger(sink, args.log_file, iters=args.iters),
    }
    all_results[sink] = variants
    
    for w in WORKLOADS:
        print_table(w, all_results[sink], sink)

    if args.plot:
        plot_sink(sink, all_results[sink])
        plt.show()

if __name__ == "__main__":
    main()</code></pre></div>]]></content:encoded></item><item><title><![CDATA[Quantpylib Lighter Integration]]></title><link>https://www.research.hangukquant.com/p/quantpylib-lighter-integration</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantpylib-lighter-integration</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Tue, 28 Apr 2026 13:01:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Szif!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Quantpylib now officially supports the Lighter exchange, with <a href="https://github.com/hangukquant/quantpylib/blob/main/examples/example_lighter.py">full example scripts</a>, <a href="https://quantpylib.hangukquant.com/wrappers/lighter/">documentation</a> and gateway compatibility, supporting seamless composability with our <a href="https://quantpylib.hangukquant.com/scripts/market_making/">market making features.</a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c63699f4-6667-46e3-a043-c43bbd0e7977&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;HangukQuant quantpylib Github Repo&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2023-11-24T16:59:27.729Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/hangukquant-community-github-repo&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:139132009,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:29,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p>The Lighter SDK is designed to be both performance aware and intuitive, presenting a significantly improved interface over the <a href="https://github.com/elliottech/lighter-python">official package.</a> See full docs here: </p><p><a href="https://quantpylib.hangukquant.com/wrappers/lighter/">https://quantpylib.hangukquant.com/wrappers/lighter/</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Szif!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Szif!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 424w, https://substackcdn.com/image/fetch/$s_!Szif!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 848w, https://substackcdn.com/image/fetch/$s_!Szif!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!Szif!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Szif!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png" width="1456" height="1255" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1255,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1069769,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/195745940?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Szif!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 424w, https://substackcdn.com/image/fetch/$s_!Szif!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 848w, https://substackcdn.com/image/fetch/$s_!Szif!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 1272w, https://substackcdn.com/image/fetch/$s_!Szif!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80d876fa-5d19-4280-b397-945a592338ab_1896x1634.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>and our market making tutorial here:</p><p><a href="https://quantpylib.hangukquant.com/scripts/market_making/">https://quantpylib.hangukquant.com/scripts/market_making/</a></p><p><strong>We will update our polymarket SDK to follow the v2 integration soon.</strong></p><p>Cheers!</p>]]></content:encoded></item><item><title><![CDATA[Quantpylib RWA Integration (Databento)]]></title><link>https://www.research.hangukquant.com/p/quantpylib-rwa-integration-databento</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/quantpylib-rwa-integration-databento</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 17 Apr 2026 13:37:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IhGk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Our research blog&#8217;s lifetime subscription is available at 40% off for another 3 days.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c5410b1f-5a98-45cc-96c4-f627a0559884&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;40% off Lifetime, 7 Days&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-04-13T13:31:15.928Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!W_yf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d6dd49f-6f37-4dbb-a3be-49495a7bef32_1316x662.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/40-off-lifetime-7-days&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:194069197,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:7,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>As a continuation of the hip-3 perp dex integrations, </p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f67ce6a7-bbc0-4d3b-824e-f0c297f82d00&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Quantpylib Update (hyperliquid docs, examples and ws)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-04-06T13:25:50.880Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!9jK9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a94e48c-5ace-411e-be3a-a32e3f778e60_1783x1396.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/quantpylib-update-hyperliquid-docs&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:193349933,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:4,&quot;comment_count&quot;:0,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>quantpylib now features Databento&#8217;s live dataset integration with the same init-subscribe-handler pipeline:</p><p><br><strong><a href="https://quantpylib.hangukquant.com/wrappers/databento/">See docs and example script here:</a></strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IhGk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IhGk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 424w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 848w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 1272w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IhGk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png" width="1456" height="1064" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1064,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:652581,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/194517911?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IhGk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 424w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 848w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 1272w, https://substackcdn.com/image/fetch/$s_!IhGk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69ab3ea-d793-49bf-8434-da6324196d2a_2682x1960.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We have also improved the order tracking features of our OMS utility library. To learn how to experiment with <em>market making in just 300 lines of code</em> with quantpylib, <a href="https://quantpylib.hangukquant.com/scripts/market_making/">see our tutorial here.</a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Optimising the hyperliquid-python-sdk]]></title><description><![CDATA[Getting 2.5ms order signing to <0.1ms.]]></description><link>https://www.research.hangukquant.com/p/optimising-the-hyperliquid-python</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/optimising-the-hyperliquid-python</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Sun, 12 Apr 2026 12:31:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XjkE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The following are all implemented optimizations <a href="https://quantpylib.hangukquant.com/wrappers/hyperliquid/">in the quantpylib&#8217;s hyperliquid wrapper.</a><br><br>For a pedestrian signing of a hyperliquid l1-payload such as order actions, the latency cost is a <strong>couple of ms</strong>. Over a simple experiment of 1000 iterations, a rough latency percentile benchmark gives <strong>2.39-2.57ms in p50-p99 latency.</strong></p><p>That is <strong>practically the network latency</strong> of getting a market data payload from Binance through a cdn, which you might be doing if you are a mm anyway.</p><p>We can do much better.</p><p>In instances <strong>where orders are not preemptively signed,</strong> order signing lives directly on the hot path. Hyperliquid&#8217;s signing path (from <a href="https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/master/hyperliquid/utils/signing.py">signing.py)</a> is a pipeline of <strong>canonicalization and hashing</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2K9v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2K9v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 424w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 848w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 1272w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2K9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png" width="1010" height="200" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:1010,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54603,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/193941794?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2K9v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 424w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 848w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 1272w, https://substackcdn.com/image/fetch/$s_!2K9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a59f506-41e6-4ae3-8a06-e85f6484b97f_1010x200.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XjkE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XjkE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 424w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 848w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 1272w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XjkE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png" width="996" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:996,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79588,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/193941794?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XjkE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 424w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 848w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 1272w, https://substackcdn.com/image/fetch/$s_!XjkE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2a2bb3d-6247-427e-b6a3-b6b0ee5a353f_996x400.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>EIP-712 encoding</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uh6Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uh6Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 424w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 848w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 1272w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uh6Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png" width="996" height="898" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:898,&quot;width&quot;:996,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:130343,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/193941794?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uh6Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 424w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 848w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 1272w, https://substackcdn.com/image/fetch/$s_!uh6Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F924d91c7-505b-4a0c-a25d-06c2760c995c_996x898.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>and finally, secp256k1 signing.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UD7f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UD7f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 424w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 848w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 1272w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UD7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png" width="1002" height="160" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:160,&quot;width&quot;:1002,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:94830,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.research.hangukquant.com/i/193941794?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UD7f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 424w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 848w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 1272w, https://substackcdn.com/image/fetch/$s_!UD7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ffba2f-66a2-4655-8516-946671a2d60b_1002x160.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Optimising this pipeline is a simple matter of appreciating the schema of an EIP712 payload, Ethereum&#8217;s structured-data signing format. The signer is given a typed message with 4 pieces:</p><ul><li><p><code>domain</code>: identifies the application / signing domain</p></li><li><p><code>types</code>: declares the schema of the message</p></li><li><p><code>primaryType</code>: the top-level struct being signed</p></li><li><p><code>message</code>: the actual field values</p></li></ul><p>The eth-account takes <code>encode_typed_data</code> of these components and produces a <code>SignableMessage</code>. On each order sign, it hashes the type definition of the EIP712 domain, performs ABI validation, obtains the domain separator, computes the Agent type hash - all of which are static. </p><p>The dynamic fields go into a tiny component, the connection-id and agent hash, which is part of the final digest:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;d58848f0-701d-4c5d-b11f-a950c358c2c4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">keccak(&#8221;\x19\x01&#8221; || domain_separator || struct_hash)</code></pre></div><p>a 32-byte digest signed by secp256k1. Between parsing the schema, walking the dictionary fields, ABI encoding and object creation/allocation - most of which are static per order - our hot path is not so hot anymore. If we can surgically stick to hashing only the dynamic components, our working set is a lot smaller.</p><p>Last but not least, significant performance degradations arise when we rely on native eth-account backend to perform signing. Elliptic curve signing relies on mathematically nontrivial operations, requiring large-integer modular arithmetic and scalar multiplication. </p><p><strong>Following the &#8216;everything is object&#8217; design</strong>, simple arithmetic such as &#8216;+&#8217; requires namespace lookup, operator dispatch, pointer chasing, heap allocation and refcount churn in Python - cryptographic operations implemented at the Python layer is terrible news for low latency code.</p><blockquote><p>Wow, Everything is Computer - President Donald Trump</p><p>Wow, Everything is Object - Python Engineer</p></blockquote><p>Again, appreciating this truth is 90% of the job done - we can find solutions to push the cryptographic work from Python runtime into a secp256k1 backend optimised in C, such as the <a href="https://github.com/bitcoin-core/secp256k1">bitcoin-core library.</a> Writing a tiny Python binding around it is the remaining 10%&#8230;oh wait, <a href="https://github.com/ofek/coincurve">it already exists.</a></p><p>Bringing it all together, we can now replace our <code>sign_l1_action</code> with <code>sign_l1_action_fast</code>. </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;fff80744-758b-404d-8fd8-7d98a0733dfe&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from coincurve import PrivateKey

_EIP712DOMAIN_TYPEHASH = keccak(b"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
_DOMAIN_SEPARATOR = keccak(
    _EIP712DOMAIN_TYPEHASH
    + keccak(b"Exchange")
    + keccak(b"1")
    + (1337).to_bytes(32, "big")
    + b'\x00' * 32
)
_AGENT_TYPEHASH = keccak(b"Agent(string source,bytes32 connectionId)")
_SOURCE_A = keccak(b"a")
_SOURCE_B = keccak(b"b")

def sign_l1_action_fast(ccwallet, action, vault_prefix, nonce, source_prefix, expires_after):
    data = msgpack.packb(action)
    data += nonce.to_bytes(8, "big")
    data += vault_prefix
    if expires_after is not None:
        data += b"\x00" + expires_after.to_bytes(8, "big")
    connection_id = keccak(data)
    agent_hash = keccak(_AGENT_TYPEHASH + source_prefix + connection_id)
    digest = keccak(b"\x19\x01" + _DOMAIN_SEPARATOR + agent_hash)
    sig = ccwallet.sign_recoverable(digest, hasher=None)
    return {"r": to_hex(sig[:32]), "s": to_hex(sig[32:64]), "v": sig[64] + 27}

class Hyperliquid:
    def __init__(self...):
        ...
        self.ccwallet = PrivateKey(self.wallet.key)
        self._vault_prefix = b"\x00" if self.vault_address is None else (b"\x01" + address_to_bytes(self.vault_address))
        self._src_prefix = _SOURCE_A if self.is_mainnet else _SOURCE_B</code></pre></div><p>and there we go! Using a faster implementation of cryptographic signatures is most of the speedup, giving us <strong>0.29-0.32ms </strong>in the same experiment. Using the pre-computed cache values gives a further 4-fold speedup, @ <strong>0.08-0.09ms.</strong></p><p><em>And that wasn&#8217;t even that hard&#8230;a simple trick in the Python Houdini</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ELEQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ELEQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ELEQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg" width="500" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ELEQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ELEQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbd6ba83-5efe-4ea5-b843-2a6280ecc467_500x500.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>]]></content:encoded></item><item><title><![CDATA[2 Years, 1M PnL and Life as a Solo Crypto Quant]]></title><description><![CDATA[Road to 50 Sharpe]]></description><link>https://www.research.hangukquant.com/p/2-years-1m-pnl-and-life-as-a-solo</link><guid isPermaLink="false">https://www.research.hangukquant.com/p/2-years-1m-pnl-and-life-as-a-solo</guid><dc:creator><![CDATA[HangukQuant]]></dc:creator><pubDate>Fri, 10 Apr 2026 16:15:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Lvvp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Lvvp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Lvvp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Lvvp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg" width="1200" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Image" title="Image" srcset="https://substackcdn.com/image/fetch/$s_!Lvvp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Lvvp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6fa10f-5aa8-4f78-89e1-1eae828b892e_1200x480.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is a <a href="https://x.com/HangukQuant/status/2042545298875318397">RT of an article I wrote on X.</a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c96dcaf4-dbe8-4aa3-a129-333f2dfa0e3c&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Crypto Arbitrage (1 Week Setup) - Coming&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:42788676,&quot;name&quot;:&quot;HangukQuant&quot;,&quot;bio&quot;:&quot;quant research and quant dev. not financial advice.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/733e6c1a-d932-4d0f-8f5a-4fa0c33d8d29_4096x2528.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2024-04-09T18:29:01.571Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Tv3A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89ff058b-13b5-4053-b93f-846e27a1a13c_2889x1456.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.research.hangukquant.com/p/crypto-arbitrage-1-week-setup-coming&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:143424317,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:13,&quot;comment_count&quot;:3,&quot;publication_id&quot;:453792,&quot;publication_name&quot;:&quot;HangukQuant Research&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!LX9y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5718e3-074f-4c1d-a77d-f1fa609a9ea0_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Exactly 2 years ago, on this date - I took a step into the treacherous crypto order books. My first foray into crypto trading was a quasi systematic funding arbitrage strategy, which I executed by hand using some spaghetti code dashboard to filter for funding pairs on binance-hyperliquid.</p><h2><strong>1 to 10 Sharpe</strong></h2><p>In those days, funding arbitrage was already a well known strategy, but execution, variation and reach played a big factor in realised APR. New exchanges seemed to be budding left and right, with unique funding mechanisms.<br><br>This pushed me to quickly build out more exchange connectors and a gateway functionality that would allow me to automate funding arbitrage strategies across multiple exchanges in a unified interface, which would later turn out to be <a href="https://quantpylib.hangukquant.com/">the quantpylib project</a>, a code repo started by my followers and then later lead by me to be a tool for both quantitative research and trading. </p><p>At this point, other projects like ccxt and hummingbot existed, but the quantpylib project focused more on <em>connectivity and composability of features </em>without relying on an architectural framework, allowing traders with variable strategies to implement high to low frequency strategies according to their needs. It integrated binance, bybit, woox, paradex and lighter, exchanges I executed arbs across. 2.5 years later and 1000+ commits later, <em>quantpylib</em> is still a work in progress.<br><br>I had decent reach and okay execution, enough to land me in the <a href="https://x.com/HangukQuant/status/2004453365988904971?s=20">40% APR range,</a> while earning points - which ironically turned out to be even more lucrative than the pnl itself, all thanks to The El Jeffe crew. These days, with tools like <a href="https://x.com/@LorisTools">@LorisTools</a>, the scale and reach of such arbitrage strategies are extensive.</p><p>Despite the ~10 Sharpe, it was a strategy with extremely low vol, and scaling the pnl meant I had to put more of my <em>already small net worth</em> on chain, a risk I was not willing to take. It also took many man hours of attention, taking time away from investing in my own technical capabilities. In young, 'skilled' workers, knowledge compounds over the remaining career lifespan.</p><h2><strong>I shut it down.</strong></h2><p>At the same time, I  was in a desperate struggle with my own mental faculties.  I was, at heart, a builder. I built things in public, in an industry where large doses of skepticism were warranted. <em>I had the imposter syndrome bug. Was I just a peddler of snake oil?  </em>Some people (including those I admired) and the anti-substack mob seemed to think so. </p><p><em>Hanguk&#8217;s income is from his newsletter. All he can do is implement a momentum trading strategy. I find it funny that Hanguk teaches systematic funding arbitrage but has to record pnl manually. </em></p><p><em>You write on a blog, I do this for a living, I would know.</em></p><p>I saw it in X replies, Discord channels, Reddit communities. Maybe I am just a fucking fraud, and I will never be <em>that guy. </em>After all, trading is an incredibly competitive industry, and greater man than me have failed. I am still young, and I can still pivot into being a quant trader where all my friends are. I could get referrals, I would be &#8216;in the industry&#8217; and I won&#8217;t have to deal with all these bullshit.</p><p>These dark thoughts would later crescendo into anxiety and panic attacks. By all counts, my &#8216;online blog&#8217; was bringing me 200k+ in ARR, and my trading was comparably rewarding. I was living my life. <em>I once had no income and no pnl, and had an unshakeable confidence that I would &#8216;figure it out&#8217;. </em>Having somewhat <em>figured it out, </em>it turned out that there were many cracks in this facade. Crypto strats were going to be squeezed by TradFi, and AI was going to wipe me out, who needs &#8216;research&#8217; when everyone had a PhD-expert on their fingertips?</p><h2><strong>Wakeup, Doomer</strong></h2><p>The truth is, there were many people supporting me. For every nasty comment, there were ten others who cheered my work on. </p><p>Claude Mythos, OpenGod or whatever - I was well equipped and adaptable enough to thrive in a post-intelligent economy. I spent some time talking to my Dad, who had the wisdom of life to slap the doomer out of me. </p><p>It&#8217;s all in your head.</p><p>I got over it by biasing towards action. Day after day, I would wake up in sweats and palpitations, and before the darkness paralysed me, I would have done a handful of pushups, hopped in the shower, and was headed out to write some code. If I kept moving, it couldn&#8217;t catch me. It took a few months, and slowly but surely, I was okay again. </p><p>Fear is good marketing. Do not be the product.</p><h2><strong>10 to 50 Sharpe</strong></h2><p>In the months to follow, I would have the most productive schedule of my life. <br>I had always wanted to go from mid-frequency to high-frequency strategies. I wanted to be knowledgeable in niche domains and be a respected engineer. There was a lot more to learn, and my mind was liberated.</p><p>I worked on hft research, tooling, infrastructure and trading. I built new features on quantpylib, picked up C++, sharpened my mathematical knowledge and was allowed to be dumb again.<br><br>I was new, and publicly so.  It had been awhile, but I was in love again. I read, I experimented, I asked and made mistakes. I basked in the wealth of knowledge. I didn&#8217;t have a PhD at my fingertips to replace me. I had one to teach me.<br><br>The best way to learn is by doing. In my frenzy of learning, researching and experimenting, I arrived at my next gold mine. Months of research, screaming at the monitor - I got my next reward, my first (successful, I had many unsuccessful ones) HFT strategy:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DCQT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DCQT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DCQT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg" width="900" height="506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:506,&quot;width&quot;:900,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Image" title="Image" srcset="https://substackcdn.com/image/fetch/$s_!DCQT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DCQT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37882aa6-a6af-4b45-8549-8985ff1ee9a0_900x506.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I consistently topped the leaderboards, fin-fluencers were writing nonsense threads about me, and I felt ... vindicated.</p><h3>Sunset</h3><p>When the sun rises, it must set. </p><blockquote><p>There&#8217;s no such thing as the goose that lays the golden egg forever. - Jim Simons, Renaissance Technologies</p></blockquote><p>Nowadays, I battle with the immortality of the goose. I hesitated if I should write this article. I&#8217;m hanging in there, but I am no longer a leaderboard resident.</p><p>As the sun sets, I am dumb again. But there is more iron in me.</p>]]></content:encoded></item></channel></rss>