<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>HFT &#8211; The Financial Hacker</title>
	<atom:link href="https://financial-hacker.com/tag/hft/feed/" rel="self" type="application/rss+xml" />
	<link>https://financial-hacker.com</link>
	<description>A new view on algorithmic trading</description>
	<lastBuildDate>Fri, 07 Oct 2022 11:02:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://financial-hacker.com/wp-content/uploads/2017/07/cropped-mask-32x32.jpg</url>
	<title>HFT &#8211; The Financial Hacker</title>
	<link>https://financial-hacker.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Hacking a HFT system</title>
		<link>https://financial-hacker.com/hacking-hft-systems/</link>
					<comments>https://financial-hacker.com/hacking-hft-systems/#comments</comments>
		
		<dc:creator><![CDATA[jcl]]></dc:creator>
		<pubDate>Sat, 08 Jul 2017 13:26:30 +0000</pubDate>
				<category><![CDATA[No Math]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[System Evaluation]]></category>
		<category><![CDATA[Arbitrage]]></category>
		<category><![CDATA[ES]]></category>
		<category><![CDATA[ETF]]></category>
		<category><![CDATA[HFT]]></category>
		<category><![CDATA[Latency]]></category>
		<category><![CDATA[NxCore]]></category>
		<category><![CDATA[SPY]]></category>
		<guid isPermaLink="false">http://www.financial-hacker.com/?p=2359</guid>

					<description><![CDATA[Compared with machine learning or signal processing algorithms of conventional algo trading strategies, High Frequency Trading systems can be surprisingly simple. They need not attempt to predict future prices. They know the future prices already. Or rather, they know the prices that lie in the future for other, slower market participants. Recently we got some &#8230; <a href="https://financial-hacker.com/hacking-hft-systems/" class="more-link">Continue reading<span class="screen-reader-text"> "Hacking a HFT system"</span></a>]]></description>
										<content:encoded><![CDATA[<p>Compared with machine learning or signal processing algorithms of conventional algo trading strategies, <strong>High Frequency Trading</strong> systems can be surprisingly simple. They need not attempt to predict future prices. They know the future prices already. Or rather, they know the prices that lie in the future for other, slower market participants. Recently we got some contracts for simulating HFT systems in order to determine their potential profit and maximum latency. This article is about testing HFT systems the hacker&#8217;s way.<span id="more-2359"></span></p>
<p>The HFT advantage is receiving price quotes earlier and getting orders filled faster than the majority of market participants. Its profit depends on the system&#8217;s <strong>latency</strong>, the delay between price quote and subsequent order execution at the exchange. Latency is the most relevant factor of a HFT system. It can be optimized in two ways: by minimizing the distance to the exchange, and by maximizing the speed of the trading system. The former is more important than the latter.</p>
<h3>The location</h3>
<p>Ideally, a HFT server is located directly at the exchange. And indeed most exchanges are dear selling server space in their cellars &#8211; the closer to the main network hub, the dearer the space. Electrical signals in a shielded wire travel with about 0.7 .. 0.9 times the speed of light (300 km/ms). 1 m closer to the signal source means a whopping 8 nanoseconds round-trip time advantage. How many trade opportunities disappear after 8&nbsp;ns? I don&#8217;t know, but people are willing to pay for any saved nanosecond.</p>
<p>Unfortunately (or fortunately, from a cost perspective), the HFT system that we&#8217;ll examine here can not draw advantage from colocating at the exchange. For reasons that we&#8217;ll see soon, it must trade and receive quotes from the NYSE and the CME simultaneously. There&#8217;s a high speed cable and also a microwave radio link running between both cities. The theoretically ideal location of such a HFT system is <strong>Warren, Ohio</strong>, exactly halfway between New York City and Chicago. I don&#8217;t know whether there&#8217;s a high speed node in Warren, but if it is, the distance of 357 miles to both exchanges would be equivalent to about 4 ms round-trip latency.</p>
<figure id="attachment_2392" aria-describedby="caption-attachment-2392" style="width: 840px" class="wp-caption alignnone"><a href="http://www.financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331.jpg"><img fetchpriority="high" decoding="async" class="wp-image-2392 size-large" src="http://www.financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331-1024x552.jpg" alt="" width="840" height="453" srcset="https://financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331-1024x552.jpg 1024w, https://financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331-300x162.jpg 300w, https://financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331-768x414.jpg 768w, https://financial-hacker.com/wp-content/uploads/2017/07/Warren-e1494606853331.jpg 1065w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></a><figcaption id="caption-attachment-2392" class="wp-caption-text">Warren, Ohio &#8211; HFT Mecca of the world (image by Jack Pearce / Wikipedia Commons)</figcaption></figure>
<p>Without doubt, a server in this pleasant town would come at lower cost than a server in the cellar of the New York Stock Exchange. My today&#8217;s free tip for getting rich: Buy some garage space in Warren, tap into the high speed New York-Chicago cable or radio link, and rent out server racks!</p>
<h3>The software</h3>
<p>When you&#8217;ve already invested money for the optimal location and connection of the HFT system, you&#8217;ll also want an algo trading software that matches the required speed. Commercial trading platforms &#8211; even Zorro &#8211; are normally not fast enough. And you don&#8217;t know what they do behind your back. HFT systems are therefore normally not based on a universal trading platform, but directly coded. Not in R or Python, but in a fast language, usually one of the following:</p>
<ul style="list-style-type: square;">
<li><strong>C or C++.</strong> Good combination of high level and high speed. C is easy to read, but very effective and the fastest language of all &#8211; almost as fast as machine code.</li>
<li><strong>Pentium Assembler.</strong>&nbsp;Write your algorithm in machine instructions. Faster than even C when the algorithm mostly runs in loops that can be manually optimized. There are specialists for optimizing assembler code. Disadvantage: Any programmer has a hard time to understand assembler programs written by another programmer.</li>
<li><strong>CUDA, HLSL, or GPU assembler.</strong>&nbsp;Run your algorithm on the shader pipeline of the PC&#8217;s video card. This makes sense when it is heavily based on vector and matrix operations.</li>
<li><strong>VHDL.</strong> If any software would be too slow and trade success really depends on nanoseconds, the ultimate solution is coding the system in hardware. In VHDL you can define arithmetic units, digital filters, and sequencers on a FPGA (<strong>F</strong>ield <strong>P</strong>rogrammable <strong>G</strong>ate <strong>A</strong>rray) chip with a clock rate up to several 100 MHz. The chip can be directly connected to the network interface.</li>
</ul>
<p>With exception of VHDL, especially programmers of 3D computer games are normally familar with those high-speed languages. But the standard language of HFT systems is plain C/C++. It is also used in this article.</p>
<h3>The trading algorithm</h3>
<p>Many HFT systems prey on traders by using fore-running methods. They catch your quote, buy the same asset some microseconds earlier, and sell it to you with a profit. Some exchanges prevent this in the interest of fair play, while other exchanges encourage this in the interest of earning more fees. For this article we won&#8217;t use fore-running methods, but simply exploit <a href="http://www.financial-hacker.com/build-better-strategies-part-2-model-based-systems/" target="_blank" rel="noopener">arbitrage</a> between ES and SPY. We&#8217;re assuming that our server is located in Warren, Ohio, and has a high speed connection to Chicago and to New York.</p>
<p>ES is a Chicago traded S&amp;P500 future, exposed to supply and demand. SPY is a New York traded ETF, issued by State Street in Boston and following the S&amp;P500 index (minus State Street&#8217;s fees). 1 ES Point is equivalent to 10 SPY cents, so the ES price is about ten times the SPY price. Since both assets are based on the same index, we can expect that their prices are highly correlated. There have been some publications (1) that claim this correlation will break down at low time frames, causing one asset trailing the other. We&#8217;ll check if this is true. Any shortlived ES-SPY price difference that exceeds the bid-ask spreads and trading costs constitutes an arbitrage opportunity. Our arbitrage algorithm would work this way:</p>
<ul style="list-style-type: square;">
<li>Determine the SPY-ES difference.</li>
<li>Determine its deviation from the mean.&nbsp;</li>
<li>If the deviation exceeds the ask-bid spreads plus a threshold, open positions in&nbsp;ES and SPY in opposite directions.</li>
<li>If the deviation reverses its sign and exceeds the ask-bid spreads plus a smaller threshold, close the positions.</li>
</ul>
<p>This is the barebone HFT algorithm in C. If you&#8217;ve never seen HFT code before, it might look a bit strange:</p>
<pre class="prettyprint">#define THRESHOLD  0.4  // Entry/Exit threshold 

// HFT arbitrage algorithm
// returns 0 for closing all positions
// returns 1 for opening ES long, SPY short
// returns 2 for opening ES short, SPY long
// returns -1 otherwise
int tradeHFT(double AskSPY,double BidSPY,double AskES,double BidES)
{
	double SpreadSPY = AskSPY-BidSPY, SpreadES = AskES-BidES;
	double Arbitrage = 0.5*(AskSPY+BidSPY-AskES-BidES);

	static double ArbMean = Arbitrage;	
	ArbMean = 0.999*ArbMean + 0.001*Arbitrage;
	static double Deviation = 0;
	Deviation = 0.75*Deviation + 0.25*(Arbitrage - ArbMean);

	static int Position = 0;	
	if(Position == 0) {
		if(Deviation &gt; SpreadSPY+THRESHOLD)
			return Position = 1;
		if(-Deviation &gt; SpreadES+THRESHOLD)
			return Position = 2;
	} else {
		if(Position == 1 &amp;&amp; -Deviation &gt; SpreadES+THRESHOLD/2)
			return Position = 0;
		if(Position == 2 &amp;&amp; Deviation &gt; SpreadSPY+THRESHOLD/2)
			return Position = 0;
	}
	return -1;	
}
</pre>
<p>The <strong>tradeHFT</strong> function is called from some framework &#8211; not shown here &#8211; that gets the price quotes and sends the trade orders. Parameters are the current best ask and bid prices of ES and SPY from the top of the order book (we assume here that the SPY price is multiplied with 10 so that both assets are on the same scale). The function returns a code that tells the framework whether to open or close opposite positions or to do nothing. The <strong>Arbitrage</strong> variable is the mid price difference of SPY and ES. Its mean (<strong>ArbMean</strong>) is filtered by a slow EMA, and the <strong>Deviation</strong> from the mean is also slightly filtered by a fast EMA to prevent reactions on outlier quotes. The <strong>Position</strong> variable constitutes a tiny state machine with the 3 states long, short, and nothing. The entry/exit <strong>Threshold</strong> is here set to 40 cents, equivalent to a bad SPY spread multiplied with 10. This is the only adjustable parameter of the system. If we wanted to really trade it, we had to optimize the threshold using several months&#8217; ES and SPY data.</p>
<p>This minimalistic system would be quite easy to convert to Pentium assembler or even to a FPGA chip. But it is not really necessary: Even compiled with Zorro&#8217;s lite-C compiler, the <strong>tradeHFT</strong> function executes in just about 750 nanoseconds. A strongly optimizing C compiler, like Microsoft VC++, &nbsp;gets the execution time down to 650 nanoseconds. Since the time span between two ES quotes is normally 10 microseconds or more, the speed of C is largely sufficient.</p>
<p>Our HFT experiment has to answer two questions. First, are those price differences big enough for arbitrage profit? And second, at which maximum latency will the system still work?&nbsp;</p>
<h3>The data</h3>
<p>For backtesting a HFT system, normal price data that you can freely download from brokers won&#8217;t do. You have to buy high resolution order book or BBO data (<strong>B</strong>est <strong>B</strong>id and <strong>O</strong>ffer) that includes the exchange time stamps. Without knowing the exact time when the price quote was received at the exchange, it is not possible to determine the maximum latency.</p>
<p>Some companies are recording all quotes from all exchanges and are selling this data. Any one has its specific data format, so the first challenge is to convert this to lean data files that we then evaluate with our simulation software. We&#8217;re using this very simple target format for price quotes:</p>
<pre class="prettyprint">typedef struct T1    // single tick
{
	double time; // time stamp, OLE DATE format
	float fVal;  // positive = ask price, negative = bid price	
} T1;</pre>
<p>The company watching the Chicago Mercantile Exchange delivers its data in a specific CSV format with many additional fields, of which most we don&#8217;t need here (f.i. the trade volume or the quote arrival time). Every day&#8217;s quotes are stored in one CSV file. This is the Zorro script for pulling the ES December 2016 contract out of it and converting it to a dataset of T1 price quotes:</p>
<pre class="prettyprint">//////////////////////////////////////////////////////
// Convert price history from Nanotick BBO to .t1
//////////////////////////////////////////////////////

#define STARTDAY 20161004
#define ENDDAY   20161014

string InName = "History\\CME.%08d-%08d.E.BBO-C.310.ES.csv";  // name of a day file
string OutName = "History\\ES_201610.t1";
string Code = "ESZ";	// December contract symbol

string Format = "2,,%Y%m%d,%H:%M:%S,,,s,,,s,i,,";  // Nanotick csv format
void main()
{
	int N,Row,Record,Records;
	for(N = STARTDAY; N &lt;= ENDDAY; N++)
	{
		string FileName = strf(InName,N,N+1);
		if(!file_date(FileName)) continue;
		Records = dataParse(1,Format,FileName);  // read BBO data
		printf("\n%d rows read",Records);
		dataNew(2,Records,2);  // create T1 dataset
		for(Record = 0,Row = 0; Record &lt; Records; Record++)
		{
			if(!strstr(Code,dataStr(1,Record,1))) continue; // select only records with correct symbol
			T1* t1 = dataStr(2,Row,0);  // store record in T1 format
			float Price = 0.01 * dataInt(1,Record,3);  // price in cents
			if(Price &lt; 1000) continue;  // no valid price
			string AskBid = dataStr(1,Record,2);
			if(AskBid[0] == 'B')  // negative price for Bid
				Price = -Price;
			t1-&gt;fVal = Price;
			t1-&gt;time = dataVar(1,Record,0) + 1./24.;  // add 1 hour Chicago-NY time difference
			Row++;
		}
		printf(", %d stored",Row);
		dataAppend(3,2,0,Row);  // append dataset
		if(!wait(0)) return;
	}
	dataSave(3,OutName);  // store complete dataset
}</pre>
<p>We&#8217;re converting here 10 days in October 2016 for our backtest. The script first parses the CSV file into an intermediary binary dataset, which is then converted to the T1 target format. Since the time stamps are in Chicago local time, we have to add one hour to convert them to NY time.</p>
<p>The company watching the New York Stock exchange delivers data in a highly compressed specific format named &#8220;NxCore Tape&#8221;. We&#8217;re using the Zorro NxCore plugin for converting this to another T1 list:</p>
<pre class="prettyprint">//////////////////////////////////////////////////////
// Convert price history from Nanex .nx2 to .t1
//////////////////////////////////////////////////////

#define STARTDAY 20161004
#define ENDDAY 	 20161014
#define BUFFER	 10000

string InName = "History\\%8d.GS.nx2";  // name of a single day tape
string OutName = "History\\SPY_201610.t1";
string Code = "eSPY";

int Row,Rows;

typedef struct QUOTE {
	char	Name[24];
	var	Time,Price,Size;
} QUOTE;

int callback(QUOTE *Quote)
{
	if(!strstr(Quote-&gt;Name,Code)) return 1;
	T1* t1 = dataStr(1,Row,0);  // store record in T1 format
	t1-&gt;time = Quote-&gt;Time;
	t1-&gt;fVal = Quote-&gt;Price;
	Row++; Rows++;
	if(Row &gt;= BUFFER)	{   // dataset full?
		Row = 0;
		dataAppend(2,1);    // append to dataset 2
	}
	return 1;
}


void main()
{
	dataNew(1,BUFFER,2); // create a small dataset
	login(1);            // open the NxCore plugin
	
	int N;
	for(N = STARTDAY; N &lt;= ENDDAY; N++) {
		string FileName = strf(InName,N);
		if(!file_date(FileName)) continue;
		printf("\n%s..",FileName);
		Row = Rows = 0;  // initialize global variables
		brokerCommand(SET_HISTORY,FileName); // parse the tape
		dataAppend(2,1,0,Row);  // append the rest to dataset 2
		printf("\n%d rows stored",Rows);
		if(!wait(0)) return;  // abort when [Stop] was hit
	}
	dataSave(2,OutName); // store complete dataset
}
</pre>
<p>The <strong>callback</strong> function is called by any quote in the tape file. We don&#8217;t need most of the data, so we filter out only the SPY quotes (&#8220;eSPY&#8221;).</p>
<h3>Verifying the inefficiency</h3>
<p>With data from both sources, we can now compare the ES and SPY prices in high resolution. Here&#8217;s a typical 10 seconds sample from the price curves:</p>
<figure id="attachment_2599" aria-describedby="caption-attachment-2599" style="width: 1701px" class="wp-caption alignnone"><a href="http://www.financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY.png"><img decoding="async" class="wp-image-2599 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY.png" alt="" width="1701" height="401" srcset="https://financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY.png 1701w, https://financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY-300x71.png 300w, https://financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY-768x181.png 768w, https://financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY-1024x241.png 1024w, https://financial-hacker.com/wp-content/uploads/2017/08/HFTChart_SPY-1200x283.png 1200w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></a><figcaption id="caption-attachment-2599" class="wp-caption-text">SPY (black) vs. ES (red), October 5, 2017, 10:01:25 &#8211; 10:01.35</figcaption></figure>
<p>The resolution is 1 ms. ES is plotted in $ units, SPY in 10 cents units, with a small offset so that the curves lie over each other. The prices shown are ask prices. We can see that ES moves in steps of 25 cents, SPY in steps of 1 cent. The prices are still well correlated even on a millisecond scale. ES appears to trail a tiny bit.</p>
<p>We can also see an arbitrage opportunity at the steep price step in the center at about 10:01:30. ES reacted a bit slower, but stronger on some event, probably a moderate price jump of one of the stocks of the S&amp;P 500. This event also triggered a fast sequence of oscillating SPY quotes, most likely from other HFT systems, until the situation calmed down again a few 100 ms later (the scale is not linear since time periods with no quotes are skipped). For several milliseconds the ES-SPY difference exceeded the ask-bid spread of both assets (usually 25 cents for ES and 1..4 cents for SPY). We would here ideally sell ES and buy SPY immediately after the ES price step. So we have verified that the theoretized inefficiency does really exist, at least in this sample.&nbsp;</p>
<p>The script for displaying high resolution charts:<!--?prettify linenums=true?--></p>
<pre class="prettyprint">#define ES_HISTORY	"ES_201610.t1"
#define SPY_HISTORY	"SPY_201610.t1"
#define TIMEFORMAT	"%Y%m%d %H:%M:%S"
#define FACTOR		10
#define OFFSET		3.575

void main()
{
	var StartTime = wdatef(TIMEFORMAT,"20161005 10:01:25"),
		EndTime = wdatef(TIMEFORMAT,"20161005 10:01:35");
	MaxBars = 10000;
	BarPeriod = 0.001/60.;	// 1 ms plot resolution
	Outlier = 1.002;  // filter out 0.2% outliers

	assetList("HFT.csv");
	dataLoad(1,ES_HISTORY,2);
	dataLoad(2,SPY_HISTORY,2);
	int RowES=0, RowSPY=0;
	
	while(Bar &lt; MaxBars)
	{
		var TimeES = dataVar(1,RowES,0), 
			PriceES = dataVar(1,RowES,1), 
			TimeSPY = dataVar(2,RowSPY,0), 
			PriceSPY = dataVar(2,RowSPY,1);

		if(TimeES &lt; TimeSPY) RowES++;
		else RowSPY++;

		if(min(TimeES,TimeSPY) &lt; StartTime) continue;
		if(max(TimeES,TimeSPY) &gt; EndTime) break;

		if(TimeES &lt; TimeSPY) {
			asset("ES");
			priceQuote(TimeES,PriceES);
		} else {
			asset("SPY");
			priceQuote(TimeSPY,PriceSPY);
		}
		
		asset("ES");
		if(AssetBar &gt; 0) plot("ES",AskPrice+OFFSET,LINE,RED);
		asset("SPY");
		if(AssetBar &gt; 0) plot("SPY",FACTOR*AskPrice,LINE,BLACK);
	}
}
</pre>
<p>The script first reads the two historical data files that we&#8217;ve created above, and then parses them row by row. For keeping the ES and SPY quotes in sync, we always read the quote with the smaller timestamp from the datasets (the quotes are stored in ascending timestamp order). The <strong>priceQuote</strong> function checks the prices for outliers, stores the ask price in the <strong>AskPrice</strong> variable and the ask-bid difference in <strong>Spread</strong>, and&nbsp;increases the <strong>Bar</strong> count for plotting the price curves. A bar of the curve is equivalent to 1 ms. The <strong>AssetBar</strong> variable is the last bar with a price quote of that asset, and is used here to prevent plotting before the first quote arrived.&nbsp;</p>
<h3>Testing the system</h3>
<p>For backtesting our HFT system, we only need to modify the script above a bit, and call the <strong>tradeHFT</strong> function in the loop:</p>
<pre class="prettyprint">#define LATENCY		4.0	// milliseconds

function main()
{
	var StartTime = wdatef(TIMEFORMAT,"20161005 09:30:00"),
		EndTime = wdatef(TIMEFORMAT,"20161005 15:30:00");
	MaxBars = 200000;
	BarPeriod = 0.1/60.;	// 100 ms bars 
	Outlier = 1.002;

	assetList("HFT.csv");
	dataLoad(1,ES_HISTORY,2);
	dataLoad(2,SPY_HISTORY,2);
	int RowES=0, RowSPY=0;
	
	EntryDelay = LATENCY/1000.;
	Hedge = 2;
	Fill = 8; // HFT fill mode;
	Slippage = 0;
	Lots = 100;
		
	while(Bar &lt; MaxBars)
	{
		var TimeES = dataVar(1,RowES,0), 
			PriceES = dataVar(1,RowES,1),
			TimeSPY = dataVar(2,RowSPY,0),
			PriceSPY = dataVar(2,RowSPY,1);

		if(TimeES &lt; TimeSPY) RowES++;
		else RowSPY++;

		if(min(TimeES,TimeSPY) &lt; StartTime) continue;
		if(max(TimeES,TimeSPY) &gt; EndTime) break;

		if(TimeES &lt; TimeSPY) {
			asset("ES");
			priceQuote(TimeES,PriceES);
		} else {
			asset("SPY");
			priceQuote(TimeSPY,FACTOR*PriceSPY);
		}
		
		asset("ES");
		if(!AssetBar) continue;
		var AskES = AskPrice, BidES = AskPrice-Spread;
		asset("SPY");
		if(!AssetBar) continue;
		var AskSPY = AskPrice, BidSPY = AskPrice-Spread;

		int Order = tradeHFT(AskSPY,BidSPY,AskES,BidES);	
		switch(Order) {
			case 1: 
			asset("ES"); enterLong();
			asset("SPY"); enterShort();
			break;
		
			case 2: 
			asset("ES"); enterShort();
			asset("SPY"); enterLong();
			break;
		
			case 0:
			asset("ES"); exitLong(); exitShort();
			asset("SPY"); exitLong(); exitShort();
			break;
		}
	}
	printf("\nProfit %.2f at NY Time %s",
		Equity,strdate(TIMEFORMAT,dataVar(1,RowES,0)));
}
</pre>
<p>This script runs a HFT backtest of one trading day, from 9:30 until 15:30 New York time. We can see that it just calls the HFT function with the ES and SPY prices, then executes the returned code in the switch-case statement. It opens 100 units of each asset (equivalent to 2 ES and 1000 SPY contracts). The round-trip latency is set up with the <strong>EntryDelay</strong> variable. In HFT mode (<strong>Fill = 8</strong>), a trade is filled at the most recent price quote after the given delay. This ensures a realistic latency simulation when price quotes are entered with their exchange time stamps.</p>
<p>Here&#8217;s the HFT profit at the end of the day with different round-trip latency values:</p>
<table style="background-color: #e8e6e6;">
<tbody>
<tr>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">LATENCY</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">0.5 ms</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">4.0 ms</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">6.0 ms</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">10&nbsp;ms</span></strong></td>
</tr>
<tr>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">Profit / day</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">+ $793</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">+ $273</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">+ $205</span></strong></td>
<td><strong><span style="font-family: arial, helvetica, sans-serif;">&#8211; $15</span></strong></td>
</tr>
</tbody>
</table>
<p>The ES-SPY HFT arbitrage system makes about $800 each day with an unrealistic small latency of 500 microseconds. Unfortunately, due to the 700 miles between the NYSE and the CME, you&#8217;d need a time machine for that (or some faster-than-light method of quantum teleportation). A HFT server in Warren, Ohio, at 4 ms latency would generate about $300 per day. A server slightly off the direct NY-Chicago line can still grind out $200 daily. But the system deteriorates quickly when located further away, as with a server in Nashville, Tennessee, at around 10 ms latency. This is a strong hint that some high-speed systems in the proximity of both exchanges are already busy with exploiting ES-SPY arbitrage.</p>
<p>Still, $300 per day result in a decent $75,000 annual income. However, what needed you to invest for that, aside from hardware and software? With SPY at $250, the 100 units translate to 100*$2500 + 100*10*$250 = half a million dollars trade volume. So you would get only 15% annual return on your investment. But you can improve this by adding more pairs of NY ETFs and their equivalent CME futures to the arbitrage strategy. And you can improve it further when you find a broker or similar service that can receive your orders directly at the exchanges. Due to the ETF/future hedging the position is almost without risk. So you could probably negotiate a large leverage. And also a flat monthly fee, since broker commissions were not included in the test.</p>
<h3>Conclusion&nbsp;</h3>
<ul style="list-style-type: square;">
<li>When systems react fast enough, profits can be achieved with very primitive methods, such as arbitrage between highly correlated assets.</li>
<li>Location has a large impact on HFT profits.</li>
<li>ES-SPY arbitrage cannot be traded by everyone from everywhere. You&#8217;re competing with people that are doing this already. Possibly in Warren, Ohio.</li>
</ul>
<p>I&#8217;ve added the scripts and the asset list to the 2017 script archive in the &#8220;HFT&#8221; and &#8220;History&#8221; folders. Unfortunately I could not add the ES / SPY price history files, since I do not own the data. For reproducing the results, get BBO history from Nanex<img src="https://s.w.org/images/core/emoji/15.0.3/72x72/2122.png" alt="™" class="wp-smiley" style="height: 1em; max-height: 1em;" /> or Nanotick<img src="https://s.w.org/images/core/emoji/15.0.3/72x72/2122.png" alt="™" class="wp-smiley" style="height: 1em; max-height: 1em;" /> &#8211; their data can be read with the scripts above. You&#8217;ll also need Zorro S version 1.60 or above, which supports HFT fill mode.</p>
<h3>References</h3>
<p>(1)&nbsp;<a href="http://jaredbernsteinblog.com/trading-in-milliseconds-when-correlations-break-down/" target="_blank" rel="noopener">When Correlations Break Down</a> (Jared Bernstein 2014)</p>
<p>(2) <a href="http://www.automatedtrader.net" target="_blank" rel="noopener">Financial Programming Greatly Accelerated</a> (Cousin/Weston, Automated Trader 42/2017)</p>
<p>&nbsp;</p>
<hr>
<p><strong>Addendum.</strong> I have been asked how the profit would be affected when the server is located in New York, with 0.25 ms signal delay to the NYSE and 4.8 ms signal delay to the CME. For simulating this, modify the script:</p>
<pre class="prettyprint">var TimeES = dataVar(1,RowES,0)+4.8/(1000*60*60*24),
&nbsp; TimeSPY = dataVar(2,RowSPY,0)+0.25/(1000*60*60*24),
...
switch(Order) {
	case 1: 
		EntryDelay = 4.8/1000;
		asset("ES"); enterLong();
		EntryDelay = 0.25/1000;
		asset("SPY"); enterShort();
		break;
		
	case 2: 
		EntryDelay = 4.8/1000;
		asset("ES"); enterShort();
		EntryDelay = 0.25/1000;
		asset("SPY"); enterLong();
		break;
		
	case 0:
		EntryDelay = 4.8/1000;
		asset("ES"); exitLong(); exitShort();
		EntryDelay = 0.25/1000;
		asset("SPY"); exitLong(); exitShort();
		break;
}</pre>
<p>The first line simulates the price quote arrivals with 4.8 and 0.25 ms delay, the other lines establish the different order delays for SPY and ES. Alternatively, you could artificially delay the incoming SPY quotes by another 4.55 ms, so that their time stamps again match the ES quotes. In both cases the system returns about $240 per day, almost as much as in Warren. However a similar system located in Aurora, close to Chicago (swap the delays in the script), would produce zero profit. The asymmetry is caused by the relatively long constant periods of ES, making the SPY latency more relevant for the money at the end of the day.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/hacking-hft-systems/feed/</wfw:commentRss>
			<slash:comments>102</slash:comments>
		
		
			</item>
		<item>
		<title>Is &#8220;Scalping&#8221; Irrational?</title>
		<link>https://financial-hacker.com/is-scalping-irrational/</link>
					<comments>https://financial-hacker.com/is-scalping-irrational/#comments</comments>
		
		<dc:creator><![CDATA[jcl]]></dc:creator>
		<pubDate>Fri, 09 Oct 2015 16:45:41 +0000</pubDate>
				<category><![CDATA[Indicators]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[System Evaluation]]></category>
		<category><![CDATA[Entropy]]></category>
		<category><![CDATA[Experiment]]></category>
		<category><![CDATA[HFT]]></category>
		<category><![CDATA[Information]]></category>
		<category><![CDATA[Shannon]]></category>
		<category><![CDATA[Zorro]]></category>
		<guid isPermaLink="false">http://www.financial-hacker.com/?p=483</guid>

					<description><![CDATA[Clients often ask for strategies that trade on very short time frames. Some are possibly inspired by &#8220;I just made $2000 in 5 minutes&#8221; stories on trader forums. Others have heard of High Frequency Trading: the higher the frequency, the better must be the trading! The Zorro developers had been pestered for years until they &#8230; <a href="https://financial-hacker.com/is-scalping-irrational/" class="more-link">Continue reading<span class="screen-reader-text"> "Is &#8220;Scalping&#8221; Irrational?"</span></a>]]></description>
										<content:encoded><![CDATA[<p>Clients often ask for strategies that trade on <strong>very short time frames</strong>. Some are possibly inspired by &#8220;I just made $2000 in 5 minutes&#8221; stories on trader forums. Others have heard of <a href="http://www.financial-hacker.com/hacking-hft-systems/" target="_blank" rel="noopener"><strong>High Frequency Trading</strong></a>: the higher the frequency, the better must be the trading! The <strong><a href="http://www.financial-hacker.com/hackers-tools-zorro-and-r/">Zorro</a></strong> developers had been pestered for years until they finally implemented tick histories and millisecond time frames. <strong>Totally useless features?</strong> Or has short term algo trading indeed some quantifiable advantages? An experiment for looking into that matter produced a <strong>surprising result</strong>.<span id="more-483"></span></p>
<p>It is certainly tempting to earn profits within minutes. Additionally, short time frames produce more bars and trades &#8211; a great advantage for strategy development. The quality of test and training depends on the amount of data, and timely price data is always in short supply. Still, scalping &#8211; opening and closing trades in minutes or seconds &#8211; is largely considered nonsense and irrational by algo traders. Four main reasons are given:</p>
<ol>
<li>Short time frames cause high <strong>trading costs</strong> &#8211; slippage, spread, commission &#8211; in relation to the expected profit.</li>
<li>Short time frames expose more <strong>&#8216;noise&#8217;,</strong> <strong>&#8216;randomness&#8217;</strong> and <strong>&#8216;artifacts&#8217;</strong> in the price curve, which reduces profit and increases risk.</li>
<li>Any algorithms had to be individually adapted to the broker or price data provider due to <strong>price feed dependency</strong> in short time frames.</li>
<li>Algorithmic strategies usually <strong>cease working</strong> below a certain time frame.</li>
</ol>
<p>Higher costs, less profit, more risk, feed dependency, no working strategies &#8211; seemingly good arguments against scalping (HFT is a very different matter). But never trust common wisdom, especially not in trading. That&#8217;s why I had not yet added scalping to my <a href="http://www.financial-hacker.com/seventeen-popular-trade-strategies-that-i-dont-really-understand/">list of irrational trade methods</a>. I can confirm reasons number 3 and 4 from my own experiences: Below bar periods of about 10 minutes, backtests with price histories from different brokers began to produce noticeably different results. And I never managed to develop a strategy with a significantly positive walk-forward test on bar periods less than 30 minutes. But this does not mean that such a strategy does not exist. Maybe short time frames just need special trade methods?</p>
<p>So I&#8217;ve programmed an experiment for finding out once and for all if scalping is really as bad as it&#8217;s rumored to be. Then I can at least give some reasoned advice to the next client who desires a tick-triggered short-term trading strategy.</p>
<h3>Trading costs examined</h3>
<p>The first part of the experiment is easily done: a statistic of the impact of trading costs. Higher costs obviously require more profits for compensation. How many trades must you win for overcoming the trading costs at different time frames? Here&#8217;s a short script (in C, for Zorro) for answering this question:</p>
<pre class="prettyprint">function run()
{
  BarPeriod = 1;
  LookBack = 1440;
  Commission = 0.60;
  Spread = 0.5*PIP;

  int duration = 1, i = 0;
  if(!is(LOOKBACK))
    while(duration &lt;= 1440)
  { 
    var Return = abs(priceClose(0)-priceClose(duration))*PIPCost/PIP;
    var Cost = Commission*LotAmount/10000. + Spread*PIPCost/PIP;
    var Rate = ifelse(Return &gt; Cost, Cost/(2*Return) + 0.5, 1.);

    plotBar("Min Rate",i++,duration,100*Rate,AVG+BARS,RED); 
 
    if(duration &lt; 10) duration += 1;
    else if(duration &lt; 60) duration += 5;
    else if(duration &lt; 180) duration += 30;
    else duration += 60;
  }
  Bar += 100; // hack!
}</pre>
<p>This script calculates the minimum win rate to compensate the trade costs for different trade durations. We assumed here a spread of <strong>0.5 pips</strong> and a round turn commission of <strong>60 cents</strong> per 10,000 contracts &#8211; that&#8217;s average costs of a Forex trade. <strong>PIPCost/PIP</strong> in the above script is the conversion factor from a price difference to a win or loss on the account. We&#8217;re also assuming no win/loss bias: Trades shall win or lose on average the same amount. This allows us to split the <strong>Return</strong> of any trade in a win and a loss, determined by <strong>WinRate</strong>. The win is <strong>WinRate * Return</strong> and the loss is <strong>(1-WinRate) * Return</strong>. For breaking even, the win minus the loss must cover the cost. The required win rate for this is</p>
<p style="padding-left: 30px; text-align: center;"><em><strong>WinRate = Cost/(2*Return) + 0.5</strong></em></p>
<p>The win rate is averaged over all bars and plotted in a histogram of trade durations from 1 minute up to 1 day. The duration is varied in steps of 1, 5, 30, and 60 minutes. We&#8217;re entering a trade for any duration every 101 minutes (<strong>Bar += 100</strong> in the script is a hack for running the simulation in steps of 101 minutes, while still maintaining the 1-minute bar period).</p>
<p>The script needs a few seconds to run, then produces this histogram (for EUR/USD and 2015):</p>
<figure id="attachment_524" aria-describedby="caption-attachment-524" style="width: 889px" class="wp-caption alignnone"><a href="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp11.png"><img decoding="async" class="wp-image-524 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp11.png" alt="" width="889" height="513" srcset="https://financial-hacker.com/wp-content/uploads/2015/10/scalp11.png 889w, https://financial-hacker.com/wp-content/uploads/2015/10/scalp11-300x173.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /></a><figcaption id="caption-attachment-524" class="wp-caption-text">Required win rate in percent vs. trade duration in minutes</figcaption></figure>
<p>You need about <strong>53% win rate</strong> for covering the costs of 1-day trades (rightmost bar), but <strong>90% win rate </strong>for 1-minute trades! Or alternatively, a 9:1 reward to risk ratio at 50% win rate. This exceeds the best performances of real trading systems by a large amount, and seems to confirm convincingly the first reason why you better take tales by scalping heroes on trader forums with a grain of salt.</p>
<p>But what about reason number two &#8211; that short time frames are plagued with &#8216;noise&#8217; and &#8216;randomness&#8217;? Or is it maybe the other way around and some effect makes short time frames even more predictable? That&#8217;s a little harder to test.</p>
<h3>Measuring randomness</h3>
<p>&#8216;Noise&#8217; is often identified with the high-frequency components of a signal. Naturally, short time frames produce more high-frequency components than long time frames. They could be detected with a highpass filter, or eliminated with a lowpass filter. Only problem: <strong>Price curve noise</strong> is not always related to high frequencies. Noise is just the part of the curve that does not carry information about the trading signal. For cycle trading, high frequencies are the signal and low-frequency trend is the noise. So the jaggies and ripples of a short time frame price curve might be just the very inefficiencies that you want to exploit. It depends on the strategy what noise is; there is no &#8216;general price noise&#8217;.</p>
<p>Thus we need a better criteria for determining the tradeability of a price curve. That criteria is <strong>randomness</strong>. You can not trade a random market, but you can potentially trade anything that deviates from randomness. Randomness can be measured through the <strong>information content</strong> of the price curve. A good measure of information content is the <strong>Shannon Entropy</strong>. It is defined this way:</p>
<p><a href="http://www.financial-hacker.com/wp-content/uploads/2015/10/shannon.png"><img loading="lazy" decoding="async" class="wp-image-529 size-full aligncenter" src="http://www.financial-hacker.com/wp-content/uploads/2015/10/shannon.png" alt="" width="260" height="47" /></a></p>
<p>This formula basically measures disorder. A very ordered, predictable signal has low entropy. A random, unpredictable signal has high entropy. In the formula, <em><strong>P(s<sub>i</sub>)</strong></em> is the relative frequency of a certain pattern <em><strong>s<sub>i </sub></strong></em>in the signal <em><strong>S</strong></em>. The entropy is at maximum when all patterns are evenly distributed and all <em><strong>P(s<sub>i</sub>)</strong></em> have about the same value. If some patterns appear more frequently than other patterns, the entropy goes down. The signal is then less random and more predictable. The Shannon Entropy is measured in <strong>bit</strong>.</p>
<p>The problem: Zorro has tons of indicators, even the Shannon Gain, but not the Shannon Entropy! So I have no choice but to write a new indicator, which fortunately is my job anyway. This is the source code of the Shannon Entropy of a char string:</p>
<pre class="prettyprint">var ShannonEntropy(char *S,int Length)
{
  static var Hist[256];
  memset(Hist,0,256*sizeof(var));
  var Step = 1./Length;
  int i;
  for(i=0; i&lt;Length; i++) 
    Hist[S[i]] += Step;
  var H = 0;
  for(i=0;i&lt;256;i++) {
    if(Hist[i] &gt; 0.)
      H -= Hist[i]*log2(Hist[i]);
  }
  return H;
}</pre>
<p>A char has 8 bit, so 2<sup>8</sup> = 256 different chars can appear in a string. The frequency of each char is counted and stored in the <strong>Hist</strong> array. So this array contains the <em><strong>P(s<sub>i</sub>)</strong> </em>of the above entropy formula. They are multiplied with their binary logarithm and summed up; the result is <em><strong>H(S)</strong></em>, the Shannon Entropy.</p>
<p>In the above code, a char is a pattern of the signal. So we need to convert our price curve into char patterns. This is done by a second <strong>ShannonEntropy</strong> function that calls the first one:</p>
<pre class="prettyprint">var ShannonEntropy(var *Data,int Length,int PatternSize)
{
  static char S[1024]; // hack!
  int i,j;
  int Size = min(Length-PatternSize-1,1024);
  for(i=0; i&lt;Size; i++) {
    int C = 0;
    for(j=0; j&lt;PatternSize; j++) {
    if(Data[i+j] &gt; Data[i+j+1])
      C += 1&lt;&lt;j;
    }
    S[i] = C;
  }
  return ShannonEntropy(S,Size);
}</pre>
<p><strong>PatternSize</strong> determines the partitioning of the price curve. A pattern is defined by a number of price changes. Each price is either higher than the previous price, or it is not; this is a binary information and constitutes one bit of the pattern. A pattern can consist of up to 8 bits, equivalent to 256 combinations of price changes. The patterns are stored in a char string. Their entropy is then determined by calling the first <strong>ShannonEntropy</strong> function with that string (both functions have the same name, but the compiler can distinguish them from their different parameters). Patterns are generated from any price and the subsequent <strong>PatternSize</strong> prices; then the procedure is repeated with the next price. So the patterns overlap.</p>
<h3>An unexpected result</h3>
<p>Now we only need to produce a histogram of the Shannon Entropy, similar to the win rate in our first script:</p>
<pre class="prettyprint">function run()
{
  BarPeriod = 1;
  LookBack = 1440*300;
  StartWeek = 10000;
 
  int Duration = 1, i = 0;
  while(Duration &lt;= 1440)
  { 
    TimeFrame = frameSync(Duration);
    var *Prices = series(price(),300);

    if(!is(LOOKBACK) &amp;&amp; 0 == (Bar%101)) {
      var H = ShannonEntropy(Prices,300,3);
      plotBar("Randomness",i++,Duration,H,AVG+BARS,BLUE);	
    }
    if(Duration &lt; 10) Duration += 1;
    else if(Duration &lt; 60) Duration += 5;
    else if(Duration &lt; 240) Duration += 30;
    else if(Duration &lt; 720) Duration += 120;
    else Duration += 720;
  }
}</pre>
<p>The entropy is calculated for all time frames at every 101th bar, determined with the modulo function. (Why 101? In such cases I&#8217;m using odd numbers for preventing synchronization effects). I cannot use here the hack with skipping the next 100 bars as in the previous script, as skipping bars would prevent proper shifting of the price series. That&#8217;s why this script must really grind through any minute of 3 years, and needs several minutes to complete.</p>
<p>Two code lines should be explained because they are critical for measuring the entropy of daily candles using less-than-a-day bar periods:</p>
<p><strong>StartWeek = 10000;</strong></p>
<p>This starts the week at Monday midnight (<strong>1</strong> = Monday, <strong>00 00</strong> = midnight) instead of Sunday 11 pm. This line was missing at first and I wondered why the entropy of daily candles was higher than I expected. Reason:  The single Sunday hour at 11 pm counted as a full day and noticeably increased the randomness of daily candles.</p>
<p><strong>TimeFrame = frameSync(Duration);</strong></p>
<p>This synchronizes the time frame to full hours respectively days. If this is missing, the Shannon Entropy of daily candles gets again a too high value since the candles are not in sync with a day anymore. A day has often less than 1440 one-minute bars due to weekends and irregularities in the historical data.</p>
<p>The Shannon Entropy is calculated with a pattern size of 3 price changes, resulting in 8 different patterns. 3 bit is the maximum entropy for 8 patterns. As price changes are not completely random, I expected an entropy value slightly smaller than 3, steadily increasing when time frames are decreasing. However I got this interesting histogram (EUR/USD, 2013-2015, FXCM price data):</p>
<figure id="attachment_569" aria-describedby="caption-attachment-569" style="width: 637px" class="wp-caption alignnone"><a href="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp2_32.png"><img loading="lazy" decoding="async" class="wp-image-569 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp2_32.png" alt="" width="637" height="513" srcset="https://financial-hacker.com/wp-content/uploads/2015/10/scalp2_32.png 637w, https://financial-hacker.com/wp-content/uploads/2015/10/scalp2_32-300x242.png 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /></a><figcaption id="caption-attachment-569" class="wp-caption-text">Entropy vs. time frame (minutes)</figcaption></figure>
<p>The entropy is almost, but not quite 3 bit. This confirms that price patterns are not absolutely random. We can see that the 1440 minutes time frame has the lowest Shannon Entropy at about 2.9 bit. This was expected, as the daily cycle has a strong effect on the price curve, and daily candles are thus more regular than candles of other time frames. For this reason price action or price pattern algorithms often use daily candles. The entropy increases with decreasing time frames, but only down to time frames  of about ten minutes. Even lower time frames are actually less random!</p>
<p>This is an unexpected result. The lower the time frame, the less price quotes does it contain, so the impact of chance should be in fact higher. But the opposite is the case. I could produce similar results with other patterns of 4 and 5 bit, and also with other assets. For making sure I continued the experiment with a different, tick-based price history and even shorter time frames of 2, 5, 10, 15, 30, 45, and 60 seconds (Zorro&#8217;s &#8220;useless&#8221; micro time frames now came in handy, after all):</p>
<figure id="attachment_601" aria-describedby="caption-attachment-601" style="width: 205px" class="wp-caption alignnone"><a href="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp2_41.png"><img loading="lazy" decoding="async" class="wp-image-601 size-full" src="http://www.financial-hacker.com/wp-content/uploads/2015/10/scalp2_41.png" alt="" width="205" height="513" srcset="https://financial-hacker.com/wp-content/uploads/2015/10/scalp2_41.png 205w, https://financial-hacker.com/wp-content/uploads/2015/10/scalp2_41-120x300.png 120w" sizes="(max-width: 205px) 85vw, 205px" /></a><figcaption id="caption-attachment-601" class="wp-caption-text">Entropy vs. time frame (seconds)</figcaption></figure>
<p>The x axis is now in second units instead of minutes. We see that price randomness continues to drop with the time frame.</p>
<p>There are several possible explanations. Price granularity is higher at low time frames due to the smaller number of ticks. High-volume trades are often split into many small parts (&#8216;<strong>iceberg trades</strong>&#8216;) and may cause a sequence of similar price quotes in short intervals. All this reduces the price entropy of short time frames. But it does not necessarily increase trade opportunities:  A series of identical quotes has zero entropy and is 100% predictable, but can not be traded. Of course, iceberg trades are still an interesting inefficiency that could theoretically be exploited &#8211; if it weren&#8217;t for the high trading costs. So that&#8217;s something to look further into only when you have direct market access and no broker fees.</p>
<p>I have again uploaded the scripts to the 2015 scripts collection. You&#8217;ll need Zorro 1.36 or above for reproducing the results. Zorro S and tick based data are needed for the second time frames.</p>
<h3>Conclusions</h3>
<ul style="list-style-type: square;">
<li>Scalping is not completely nuts. Very low time frames expose some regularity.</li>
<li>Whatever the reason, this regularity can not be exploited by retail traders due to the high costs of short term trades.</li>
<li>On time frames above 60 minutes prices become less random and more regular. This recommends long time frames for algo trading.</li>
<li>The most regular price patterns appear with 1-day bars. They also cause the least trading costs.</li>
</ul>
<h3>Papers</h3>
<p>Shannon Entropy: <a href="http://www.ueltschi.org/teaching/chapShannon.pdf" target="_blank" rel="noopener noreferrer">Lecture</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://financial-hacker.com/is-scalping-irrational/feed/</wfw:commentRss>
			<slash:comments>24</slash:comments>
		
		
			</item>
	</channel>
</rss>
