Easy Mean/Median Quantile Creation (Python Code)

Screen Shot 2016-01-30 at 3.05.13 PM

I’ve been teaching myself Python, and I’ve had a couple of successes recently where I took a concept or “need” and coded it to completion. Yay, me!

One thing I find myself doing a lot is sorting a batch of data by one column in Excel/Google Sheets, then dividing up another column into quantiles and averaging each quantile for later graphing. This a research technique I use a lot with financial data.

Continue reading Easy Mean/Median Quantile Creation (Python Code)

AmiBroker Code for the Breadth Indicator

30qtrindicator 3

As per request, I’m including the AmiBroker code for the “30% up/down last quarter in the Russell 3000 index” indicator. I REALLY need to come up with a better name for it than that. How about the Haines Breadth Indicator? No, that’s  stupid. Magic Matt’s Mystical Meter? Uh…sure.

It’s a two step process. You must do a scan every day, or as frequently as you want accurate data. It doesn’t hurt if you’re away on vacation and miss a few days, as AmiBroker will fill in the gaps when you return. The scan counts up all the stocks meeting your criteria, and writes these to separate ‘composite’ files that are then read back in by the indicator. You use this with the ‘explore’ process.

xx=IsIndexConstituent("$RUA");

AddToComposite(C/LLV(C,60)>=1.3 AND xx,"~POS30QTR","X",19);
AddToComposite(C/HHV(C,60)<=.7 AND xx,"~NEG30QTR","X",19);

// above is the breadth measurement that showed the most promise.
//You could comment out all the other indicators and
//possibly speed things up.

AddToComposite(C/Ref(C,-1)>=1.04 AND xx,"~POS4DAILY","X",19);
AddToComposite(C/Ref(C,-1)<=.96 AND xx,"~NEG4DAILY","X",19);
AddToComposite(C/LLV(C,20)>=1.2 AND xx,"~POS20MO","X",19);
AddToComposite(C/HHV(C,20)<=.8 AND xx,"~NEG20MO","X",19);
AddToComposite(L==LLV(L,60) AND xx,"~NEWLOW60","X",19);
AddToComposite(H==HHV(H,60) AND xx,"~NEWHI60","X",19);




myrsi=RSI(2);
AddToComposite(myrsi<10 AND xx,"~LO_RSI_COMP","X",19);
AddToComposite(myrsi>90 AND xx,"~HI_RSI_COMP","X",19);

rsi14=RSI(14);
AddToComposite(rsi14<30 AND xx,"~LO_RSI14_COMP","X",19);
AddToComposite(rsi14>70 AND xx,"~HI_RSI14_COMP","X",19);



AddToComposite(C>BBandTop(C) AND xx,"~HI_BB_COMP","X",19);
AddToComposite(C<BBandBot(C) AND xx,"~LO_BB_COMP","X",19);

pos4d=Foreign("~POS4DAILY","C");
neg4d=Foreign("~NEG4DAILY","C");
pos30q=Foreign("~POS30QTR","C");
neg30q=Foreign("~NEG30QTR","C");
pos20m=Foreign("~POS20MO","C");
neg20m=Foreign("~NEG20MO","C");
spyop=Foreign("SPY","O");
spycl=Foreign("SPY","C");
newlow=Foreign("~NEWLOW60","C");
newhi=Foreign("~NEWHI60","C");
posrsi14=Foreign("~HI_RSI14_COMP","C");
negris14=Foreign("~LO_RSI14_COMP","C");



Buy=Sell=Cover=Short=0;


Filter= IsIndexConstituent("$RUA");
AddColumn(pos4d,"+4% today",1);
AddColumn(neg4d,"-4% today",1);
AddColumn(pos30q,"+30% qtr",1);
AddColumn(neg30q,"-30% qtr",1);
AddColumn(pos20m,"+20% month",1);
AddColumn(neg20m,"-20% month",1);
AddColumn(spyop,"SPY Open",1.2);
AddColumn(spycl,"SPY Close",1.2);
AddColumn(newlow,"New 60d Low",1.0);
AddColumn(newhi,"New 60d Hi",1.0);
AddColumn(pos30q/(pos30q+neg30q)*100,"30q dif",1.2);
AddColumn(newhi/(newhi+newlow)*100,"hi-lo dif",1.2);



It occurs to me that I don’t know if the first line….

xx=IsIndexConstituent("$RUA");

…works for all types of data sources. If you don’t get any results, change xx to equal “1” and use AmiBroker’s filter to select current Russell 3000 members.

I run this on a historical set of the Russell 3000 constituents, so it takes a while on my aging laptop. You could also just set AmiBroker’s filter (not the one in the code, but the one used when running an ‘explore’ job) to the current list of Russell 3000 members. Just be aware that your historical data will be subject to survivorship bias. This won’t have any effect on your current readings however…it just means your data will get less reliable as you look back in time.

If you don’t run the composite code regularly, you won’t have any recent data for your indicator to display. It won’t break though, but it won’t be valid either.

Here’s the code for the diffusion indicator. It’s actually generic in the sense that you can compare any two composites (or tickers) you want. It defaults however to the file name used for the “30% quarterly” composite index. It also defaults to a 10 day requirement for a signal to be given.

thresh1=Param("buy thresh",75,1,99,1); 
thresh2=Param("sell thresh",75,1,99,1); 
Ticker1 = ParamStr("Symbol1", "~POS30QTR" ); 
Ticker2 = ParamStr("Symbol2", "~NEG30QTR" ); 
flgrng=Param("threshold count",10,1,50,1); 
 
t1=Foreign(Ticker1,"C"); 
t2=Foreign(TIcker2,"C"); 
dif=t1/(t1+t2)*100; 
flgon=Sum(dif>thresh1,flgrng)==flgrng; 
flgoff=Sum(dif<thresh2,flgrng)==flgrng; 
 
 
Plot(dif,"Diffusion",colorTeal,styleLine|styleThick); 
Plot(thresh1,"",colorGreen); 
Plot(thresh2,"",colorRed); 
 
Plot(flgon*100,"Buy",colorGreen,styleHistogram|styleThick); 
Plot(flgoff*100,"Sell",colorRed,styleHistogram|styleThick); 
 

 

Filtering With Median Rather Than Average

Screen Shot 2015-07-16 at 11.48.11 AM

Yes I realize that might be the dullest blog post title I’ve ever come up with. Perhaps only to be topped by the dullest content ever…let’s see.

It’s quite typical when creating backtests to filter using some minimum measurement of trading volume. This ensures that you’re working with stocks that are liquid. Stocks that don’t have heavy trade volumes tend not to behave like your backtest software thinks they do. For very illiquid stocks, you may have to wait a long time to get your order filled, and market or stop orders may be subject to punitive bid/ask spreads. So when testing, you want to make sure your test eliminates these sketchy ne’er-do-well stocks.

Until recently I’ve been using a simple average (mean) of the volume. For example, I might require a stock to have an average 10-day volume greater than 100,000 shares. However I recently noticed some weird outliers skewing my results.

Averages are very sensitive to ‘tail events’. If you have nine small numbers and one big number, the big number is going to skew the average in its direction in a way that you might not have intended.

For example, see the lead image above? There’s a spike of 21.8 million shares in one day’s volume, but you can see that it’s not very typical of the stock. The 20-day average of volume is right around 1.5 million shares. However on most days the volume is well below that number.

So instead I’ve started using the median value of a series instead. I’ll use an odd number for the sample size so that I get a true median or ‘middle’ number. This gives me a value that doesn’t heavily weigh outliers, and seems more typical.

The median volume for the stock you see above is actually around 209,000 shares, which makes a whole lot more sense. If I’d been filtering out stocks under an average of 1 million shares in volume, this stock would have made it through. But when using the median value, it would have been dropped (and rightly so).

Don’t be mean. Be median.

 

Stock Market Health Indicator for ProRealTime

spy-alert-indicator

Most of the trading systems I use are for long positions, and as a result they only work when the market is in a healthy state. However different systems require different conditions to be met. For example, most of my systems (long term or swing-trade) require that the S&P 500’s 40-day moving average be greater than the 120-day moving average. However, several systems I use require not only that condition, but also that the 120-day moving average be the highest of the last 50 periods. And at least one system requires that the S&P’s Close of the previous day be greater than the 120-day moving average.

So I’ve set up a handy indicator in ProRealTime (awesome free charting software) to give me an instant view of the current market’s health. Basically, if the black line is at the top (at 3) and the bar is light green, then all conditions are hit. If the black line is lower than 3, then I need to take a closer look to see what condition is not being met.

 

First, the code:

fma=AVERAGE[40]
sma=AVERAGE[120]
level1=fma>sma
level2=sma>Highest[50](sma[1])
level3=Close>sma

RETURN level1+level2+level3 AS “combined”, level1 AS “fma>sma”, level2 AS “sma highest”, level3 AS “close above”

 

In the upper right corner of the ProRealTime chart window you’ll see the little pop-up menu icon (circled below in green). Click on the arrow and select “indicators”.

spy-alert-indicator2The Indicators window will open, and it’ll look like what you see below. Click on the “new” button at the left.

spy-alert-indicator4

Below you can see the coding section for indicators. Paste the code from the beginning of this blog post in here. Give it a catchy name at the top, like I did. Then click the big “Add indicator to chart” button in the lower right corner.

spy-alert-indicator5

The indicator will initially be a bunch of angular black lines. Let’s go fix that! Your new indicator will be in a sub-window at the bottom. Click the wrench icon in that sub-window to edit the indicator.

spy-alert-indicator3

Below you’ll see the indicator settings. The “combined” sub-indicator should be fine as a black line, but you can mess around with color and style if you’d like. But click on each of the other sub-indicators and turn their style setting to “histogram”. And pick colors for them. The lowest in the set will display in front, so I have set the “fma>sma” bar to dark green the “sma highest” bar to medium green, and “close above” to be light green.

spy-alert-indicator6Before closing the window, click on the title of your indicator on the left, then select the check box at the bottom to set these color/style settings as the default for your new indicator.

spy-alert-indicator7

I created a new template for this, so I can call everything up in one click. Select “SPY” as your ticker symbol, make sure your indicator is showing below, and then go up to the Templates menu and save a new template.

And then, very important, save your work! PRT has a funny way of not saving things before it quits on its own. Bad robot!

This is just a quick little code snippet and I might refine it later, but it’s useful to integrate into my pre-trade checklist. There’s nothing worse than committing money to a trade, only to realize you forgot to check something first. This helps me not screw it all up, and perhaps it will help you too.