Fuzzy Logic Optimization -The “WOO-FOO-SMASH-EFIS-MEE-COPT” model

Fuzzy Logic pt.3: Auto-generate model parameters

I often tire of reading these complicated academic papers that are filled with impossible jargon only to make my life harder. I have found that often times the difficult terminology only hides the simple concepts that lie behind.

So here I will use a difficult term myself,  just to sound smarter than I am. In today’s post I will implement a WFCMAESFISMICOPT( pronounced  “woo-foo-smash-efis-mee-copt”) model.
It stands for: A Walk-Forward Covariance-Matrix-Adaptation-Evolution-Strategy on a Fuzzy-Inference System On Multiple Instruments and A Custom Optimization Target. How is that for a title!

You think that’s complicated? It’s not. We ‘ll start with Matlab’s standard ANFIS model to see where the idea comes from.

Matlab’s Fuzzy Logic module includes what is called ANFIS or Adaptive Neuro-Fuzzy Inference Systems.
Now that sounds complicated too. Well it is, if you were to built it. But the concept behind it is simple.

An ANFIS system is a fuzzy model where the parameters are not set by an “expert” but are found using Neural Networks.
In a normal Fuzzy Model an “expert” is invited to give statements like
1. “I consider RSI  to be Low when  it is between 0 and 40. The closer to 0 the “Lower” it is”.
2. “A Low RSI(3) gives a possible Buy signal”.

An ANFIS system needs no expert. Given a optimizing target (i.e.,profit), it comes up with both the membership functions and the rules. So in theory it can expose relationships that humans may not be able to see. One can argue, why not use Neural Networks directly? Anfis has the advantage that once we get the results, the results are translatable to Human understandable concepts like “Buy at Low RSI and Mid-month”.

ANFIS models get bogged down at 5+ Inputs and the optimization target is usually tomorrow’s return. Matlab’s ANFIS cannot (without custom code) optimize for Profit% or CAR/MDD or Sharpe Ratio.

Now Amibroker (a Software for under \$300) can do that. It may not have Neural Nets but has something possibly better for optimizing the parameters: the CMA-ES optimizer. And it’s fast.

That means we can build the Fuzzy model in an Amibroker script and optimize all the parameters, using whatever optimizing target we want (i.e., the default CARMDD or our own custom). We can also run it on a portfolio of multiple instruments as well as Walk-Forward it so that we know it has no “prior knowledge” built into it.

Let’s look at the TRIANGULAR memberships we build before. This basically says that
if RSI(3) is between 0 and 40 it is “Low”. The close to 0 the lower it is.
if RSI(3) is between 10 and 90, its “Mid” where it’s most “Mid” at RSI(3)=50
if RSI(3) is between 60 and 100, its “High”. The closer to 100 the higher it is.

Here’s the  TRIMember function:
TRIMember(variable, leftBottom, MidHigh, RightBottom)
So these can be written as

SetMember(  “rsi3”, “Low”, TRIMember( rsi3, 0, 0, 40 ) );
SetMember(  “rsi3”, “Neutral”, TRIMember( rsi3, 10, 50, 90 ) );
SetMember(  “rsi3”, “High”, TRIMember( rsi3, 60, 100, 100 )  );
or for that matter

SetMember(  “rsi3”, “Low”, TRIMember( rsi3, a, a+b, a+b+c) );
SetMember(  “rsi3”, “Neutral”, TRIMember( rsi3, d, d+e, d+e+f) );
SetMember(  “rsi3”, “High”, TRIMember( rsi3, g, g+k, g+k+m)  );

and as Amibroker users know we can do this:
a=optimize(“a”,0,0,50,10);
b=optimize(“b”,0,0,50,10);
c=optimize(“c”,0,0,50,10);
etc…

We do have a practical problem here: Too many overlaping parameters. We can help a bit by using Membership Function with 2 parameters like Gaussian Membership Function and Sigmoid Membership function.  Or we can forget about optimizing the membership functions and just optimize the rules.

That we will do in the next post:
How to uncover hidden relationships in the markets in under 5 minutes.

* I am neither a programmer nor a fuzzy logic expert. The information given is to the best of my ability/knowledge and meant to un-intimidate and motivate self directed investors to use tools that proffesional Quants use. The information is not necessarily written with accuracy in mind but with practical usability for someone who trades.

The case for Fuzzy Logic in Trading

The more I backtest strategies the more I feel the need for robustness in a system. There is no point to optimize return. One should optimize certainty of positive return. Most strategies that do really well in the past are over complicated and over-fitted and tend to loose money.

One way to achieve robust results is to use approximate values.

You can say buy when RSI(3)<25
Or you can say Buy when  RSI(3)  is fairly Low

You can say Buy on Monday of Expiration Week
Or Buy around the middle of the month.

So here’s a system:
Buy when RSI(3) is Low and we are before Expiration week. Let’s test it.
How do we code this in
1. Matlab
2. Amibroker

1. Matlab –
First we construct a Fuzzy Model that will take 2 Inputs
a. RSI(3)
b.DayofMonth     (i.e., 1…31)

Type “fuzzy” in the Terminal and voila…
We then add a second input and name both.

Set the ranges, 0-100 for rsi3 and 1-31 for day of month.
We then move around the MF’s (memebership functions) until we come up with this:

We then come up with the rules:
If rsi is low and month is around the middle then Buy
If rsi is high and month is early Sell
if rsi is High then Sell

Here’s what the rules look like visually:

The Lower the RSI the closer to 1 the output.
The More in the middle of the month the closer to 1 the output.
Keep in mind the Output ranges from 0 to 1. Towards 1 is Buy, towards 0 is Sell.

Here’s how the fuzzy model incorporates the “Common sense” non linearity (for a simple 2 input model)

This may look “scientific” but all it does is say “I like Mid-month and Low RSI”.

So now we have our model. We will save it as “RSI3_ExpWeek_Fis.fis”.

Now on to the script. We need daily prices of SPY to calculate RSI(3) and the day number. We ‘ll get it from Yahoo.

%START CODE

ticker_fints=GetTickerV(‘SPY’,’15y’,’d’);

DatesinCode=ticker_fints.dates;
close=fts2mat(ticker_fints.close);
open=fts2mat(ticker_fints.open);
dayofmonth=day(DatesinCode);
rsi3=rsi(close,3);

inputs=[rsi3 dayofmonth];

%open the fis model

%Feed the inputs and get result (0…1)
result=evalfis(inputs,b);

%if result <0.5 Buy, else Sell
signal=iif(result>0.5,1,iif(result<0.5,-1,0));

[pnl,pnlvector, sh]= backtestlongAmount(ticker_fints,signal,’open’,1,100000);

%END CODE

So how did we do?

On the next post I will show how to code this in Amibroker.

Matlab for Amibroker Users – Backtesting Functions for Matlab

The point of this post is to provide some basic functions to non professional Matlab users that may help backtest a simple long only system the way Amibroker (and  most other software) backtest.

If you are an Amibroker user you are used to something this easy:

sma9=ma(close,9);
sma21=ma(close,21);
sell=Cross(sma21,sma9);
Wish you could do that in Matlab?
Here’s the Matlab Code for a simple Moving Average Crossover system using some custom functions

%START CODE
%You need these files in the “Path”  for the code to work
%sma.m, iif.m, Cross.m, backtestlongAmount.m, GetTickerV.m, stock.m
%Download SPY from Yahoo, 5 years history, daily bars. We get a “fints” object
% Function TickerV() is similar to function stock() except that

ticker_fints=GetTickerV(‘SPY’,’5y’,’d’);
%%Get the close price from fints and make it a vector
close=fts2mat(ticker_fints.close);
open=fts2mat(ticker_fints.open);
sma9=sma(close,9);
sma21=sma(close,21);
buy=Cross(sma9,sma21);  % custom function, NOT Matlab’s native cross( )
sell=Cross(sma21,sma9);
%Signal should be 1 for Buy, -1 for Sell and 0 for noAction (or Hold)
% Buy and Sell on next bar Open
[pnl,pnlvector, sh]= backtestlongAmount(close,signal,open,1,100000);
% [pnl,pnlvector, sh]= backtestlongAmount(close,signal,close,0,100000);
plot(pnl,’DisplayName’,’pnl’,’YDataSource’,’pnl’);figure(gcf)
%END CODE

You are free to copy the code and download the functions. I am not a professional coder. Most functions include pre-existing code that I combined and edited. It’s very probable that mistakes exist.
I am sharing these m files in hope others will check and improve them.

Disclaimer: This code may not provide accurate results. You will have to check yourself to make sure the code works as it should.

The function are:
sma.m
iif.m
Cross.m
backtestlongAmount.m
GetTickerV.m
stock.m

Custom Functions

Basic Backtest Function for Matlab

This is a very basic function for backtesting a strategy in Matlab.
All you need is a vector with 1s for Buy, -1’s for Sell and 0’s for Hold.

To use it we need
1. A vector of prices,i.e. SPY close prices
2. Signal: A vector of  1 for BUY, -1 for SELL and 0 for HOLD
3. Buyprice: A vector of Close prices if we buy at close or Open prices if we buy at Open
4. Delay: 0 if we buy “Today” – 1 if we buy tomorrow. So to Buy Tomorrow on Open:
backtestlongAmount(data,signal,open,1,amount\$\$);
4. Amount :i.e., 100,000

backtestlongAmount.m

Please report any bugs or inaccuracies you find. Improvements are welcome.