StockFetcher Forums · Filter Exchange · PANGOLIN Z AND PANGOLIN W - FULL SYSTEM CODE<< 1 2 3 4 5 ... 9 >>Post Follow-up
Kevin_in_GA
4,599 posts
msg #122431
Ignore Kevin_in_GA
12/31/2014 8:39:29 AM

As some of you know, I have been running a few subscription systems over at Collective2 since early last year. These have been successful both as a trading system and as a source of extra revenue from the subscription fees, but I have decided that for 2015 I will shut them down and spend more time sharing stuff here at SF. Truth is managing three system nightly had me spending about an hour in total getting the nightly signals out, and that was time I wanted to spend with others rather than in front of the computer (or at least doing something more satisfying on the computer than sending out the nightly signals). Since Pangolin W and Pangolin Z were originally coded in SF, and I use SF every night to put the trades together, it just makes sense to share them here as a way of getting back to what I enjoy most - sharing stuff rather than charging for it

HERE IS THE COMPLETE PANGOLIN Z SYSTEM CODE IN STOCKFETCHER

Let me start by walking you through the code line by line:

1. Define the market: I only use the S&P 500 for stock systems, as it guarantees liquidity and tight bid/ask spreads, and these stocks are unlikely to make big corrections that can pull you deep into a hole.

The SF code for this is simple:

/*DEFINE THE MARKET*/
S&P 500


2. Determine the ratio of the stock to the S&P 500 index. I use SPY here so that the filter can be checked intraday. The correlation between SPY and the ^SPX is 1.000 so it works perfectly for this application. I use a lot of user-defined variables ... they are constructed using the SET{} function to allow for various mathematical functions and tweaking to be done. As you will see, it allows for a very flexible code construction that not a lot of SF folks know how to do very well.

/*DETERMINE RATIO OF S&P STOCK TO THE ^SPX*/
SET{PRICERATIO, CLOSE / IND(SPY,CLOSE)}


3. Now take the 20 day simple moving average of the ratio. This was one of the optimized parameters. I looked at about 20 different timeframes for this, from 5 to 100 days in 5 day increments:

SET{RATIOMA20, CMA(PRICERATIO,20)}

4. Calculate the Standard Deviation and current Z-score. This is essentially putting Bollinger Bands around the price ratio - the Z-score is the number of SD away from the 20 day simple moving average.

SET{RATIOSTD20, CSTDDEV(PRICERATIO,20)}
SET{DIFF20, PRICERATIO - RATIOMA20}
SET{ZSCORE20, DIFF20 / RATIOSTD20}


5. Set up the required risk management control elements. NEVER ENTER A TRADE WITHOUT RISK CONTROLS!

/*DETERMINE THE MAXIMUM AMOUNT YOU ARE WILLING TO LOSE*/
SET{ACCOUNTSIZE, 25000}
SET{RISKLEVEL, ACCOUNTSIZE*0.005}


Here I have set up the code to put only 0.5% of your trading equity at risk on any given trade. All you need to do is set your account size at whatever the amount is that you can currently trade using this system.

/*DETERMINE LIMIT ENTRY POINT*/
SET{LIMITENTRY, MIN(CLOSE, REVERSERSI(2,5))}


Here we are using the limit entry at the price the would correspond to a RSI(2) of 5. If the stock is already below that value, you use the current close instead - that is why I use the MIN() function here as it automatically chooses the lower price of the two possible limit entries.

/* VAN THARP POSITION SIZING - SET THE STOP LOSS AND SHARE SIZE BASED ON LIMIT ENTRY AND AMOUNT WILLING TO LOSE*/
SET{2ATR, 2 * ATR(20)}
SET{STOPLOSS, LIMITENTRY - 2ATR}


I use twice the value of the ATR(20) as the point for positioning the stop loss. Just a simple subtraction of this amount from the entry price - this should give the stock enough room to fluctuate normally without triggering the stop loss.

/*DETERMINE THE NUMBER OF SHARES TO BE PURCHASED*/
SET{SHARESTOBUY1, RISKLEVEL/2ATR}
SET{SHARESTOBUY, ROUND(SHARESTOBUY1, 0)}


Just a quick comment here - SF code does not let you do more than 1 mathematical operation in any given SET{} statement. Here I have determined the required number of shares, then used the ROUND() function to make the output a whole number for ease in placing orders. When I place my orders I usually round to the nearest 5 shares since that is easier to actually get an order filled - odd amounts like 17 are harder to get filled than 15 or 20 shares.

/*TOTAL AMOUNT OF EQUITY USED IN THIS TRADE*/
SET{POSITIONAMT, LIMITENTRY * SHARESTOBUY}

/*PERCENT OF TRADING CAPITAL USED IN THIS TRADE*/
SET{POSITIONPCT1, POSITIONAMT / ACCOUNTSIZE}
SET{POSITIONPCT, POSITIONPCT1 * 100}


Keep track of these - this helps to prevent you from overcommitting funds.

6. Determine the order of selection of stocks from the nightly results. There are a lot of ways one can do this, but I prefer to use the ratio of what I can make to what I can lose (return/risk). What you will see if that as the stock price moves up, the profit target moves down until they meet. To me, that means I want the maximum amount I can make to be as large as possible at the start so that the trade stands the best chance of making decent money. As you will see a little further down, I do not want to take trades where this ratio is below 1.

/*DETERMINE THE REWARD-TO-RISK RATIO BASED ON THE PROFIT TARGET AT RSI(2) = 90*/
SET{REWARD1, REVERSERSI(2,90) - LIMITENTRY}
SET{REWARD, REWARD1 * SHARESTOBUY}
SET{R_R, REWARD / RISKLEVEL}


7. Now we tell the filter what to look for. In the original version of the filter, we simply looked for the day where the 16-day Z score crossed below -2, and sold when it crossed back above -1. What I had observed was that often the stock would stay below -2 for another day or so and that buying a little later would have been more profitable. So I ran another optimization on " X days in a row where the Z score was below Y" where I varied X and Y as well. The result - a balance of trade returns and trade frequency - was that the stock had to have a Z score below 0 for the last four days in a row. I also only trade stocks that are above their 200 day moving average. I also looked at the price action relative to a set of different Bollinger Bands - if the low for the day was below the lower BB(10,2) the results were better than any other setting, so that is one of the selection criteria as well.

/*SET THE CRITERIA NECESSARY TO TRIGGER A TRADE*/

COUNT(ZSCORE20 BELOW 0,4) ABOVE 3
LOW BELOW LOWER BOLLINGER BAND(10,2)
CLOSE ABOVE MA(200)
RSI(2) BELOW 15


8. Define the specific columns for the filter results. Here is where you specify and format the filter output.

ADD COLUMN RSI(2)
ADD COLUMN ATR(20) {ATR(20)}
ADD COLUMN SEPARATOR
ADD COLUMN SHARESTOBUY {SHARES TO BUY}
ADD COLUMN LIMITENTRY {LIMIT ENTRY}
ADD COLUMN REVERSERSI(2,90) {PROFIT TARGET}
ADD COLUMN STOPLOSS {STOP LOSS}
ADD COLUMN R_R {REWARD-TO-RISK}
ADD COLUMN POSITIONAMT {POSITION SIZE IN DOLLARS}
ADD COLUMN POSITIONPCT {PERCENT OF TRADING EQUITY}

SORT ON COLUMN 12 DESCENDING


9. Now add some "bells and whistles" to the charts. This part lets you quickly see the entry and exit price

DRAW PRICE LINE AT LIMITENTRY ON PLOT PRICE
DRAW PRICE LINE AT REVERSERSI(2,90) ON PLOT PRICE
DRAW RSI(2) LINE AT 5
DRAW RSI(2) LINE AT 90
DRAW BOLLINGER BANDS(10,2)
DRAW ZSCORE20 LINE AT 0
CHART-TIME IS 3 MONTHS



10. Putting it all together into a single filter. You can now just cut and paste the code below into a new filter on SF, and you have the Pangolin Z system. For determining the new RSI(2)-based profit target each night you simply set up a watchlist of the stocks you are holding and add a column with "add column reversersi(2,90) {profit target}". This will automatically update the dynamic exit for the next day.

Fetcher[
/*DEFINE THE MARKET*/
S&P 500

/*DETERMINE RATIO OF S&P STOCK TO THE ^SPX*/
SET{PRICERATIO, CLOSE / IND(SPY,CLOSE)}

SET{RATIOMA20, CMA(PRICERATIO,20)}

SET{RATIOSTD20, CSTDDEV(PRICERATIO,20)}
SET{DIFF20, PRICERATIO - RATIOMA20}
SET{ZSCORE20, DIFF20 / RATIOSTD20}

/*DETERMINE THE MAXIMUM AMOUNT YOU ARE WILLING TO LOSE*/
SET{ACCOUNTSIZE, 25000}
SET{RISKLEVEL, ACCOUNTSIZE*0.005}

/*DETERMINE LIMIT ENTRY POINT*/
SET{LIMITENTRY, MIN(CLOSE, REVERSERSI(2,5))}

/* VAN THARP POSITION SIZING - SET THE STOP LOSS AND SHARE SIZE BASED ON LIMIT ENTRY AND AMOUNT WILLING TO LOSE*/
SET{2ATR, 2 * ATR(20)}
SET{STOPLOSS, LIMITENTRY - 2ATR}

/*DETERMINE THE NUMBER OF SHARES TO BE PURCHASED*/
SET{SHARESTOBUY1, RISKLEVEL/2ATR}
SET{SHARESTOBUY, ROUND(SHARESTOBUY1, 0)}

/*TOTAL AMOUNT OF EQUITY USED IN THIS TRADE*/
SET{POSITIONAMT, LIMITENTRY * SHARESTOBUY}

/*PERCENT OF TRADING CAPITAL USED IN THIS TRADE*/
SET{POSITIONPCT1, POSITIONAMT / ACCOUNTSIZE}
SET{POSITIONPCT, POSITIONPCT1 * 100}

/*DETERMINE THE REWARD-TO-RISK RATIO BASED ON THE PROFIT TARGET AT RSI(2) = 90*/
SET{REWARD1, REVERSERSI(2,90) - LIMITENTRY}
SET{REWARD, REWARD1 * SHARESTOBUY}
SET{R_R, REWARD / RISKLEVEL}

/*SET THE CRITERIA NECESSARY TO TRIGGER A TRADE*/

COUNT(ZSCORE20 BELOW 0,4) ABOVE 3
LOW BELOW LOWER BOLLINGER BAND(10,2)
CLOSE ABOVE MA(200)
RSI(2) BELOW 15

ADD COLUMN RSI(2)
ADD COLUMN ATR(20) {ATR(20)}
ADD COLUMN SEPARATOR
ADD COLUMN SHARESTOBUY {SHARES TO BUY}
ADD COLUMN LIMITENTRY {LIMIT ENTRY}
ADD COLUMN REVERSERSI(2,90) {PROFIT TARGET}
ADD COLUMN STOPLOSS {STOP LOSS}
ADD COLUMN R_R {REWARD-TO-RISK}
ADD COLUMN POSITIONAMT {POSITION SIZE IN DOLLARS}
ADD COLUMN POSITIONPCT {PERCENT OF TRADING EQUITY}

SORT ON COLUMN 12 DESCENDING

DRAW PRICE LINE AT LIMITENTRY ON PLOT PRICE

DRAW PRICE LINE AT REVERSERSI(2,90) ON PLOT PRICE
DRAW RSI(2) LINE AT 5
DRAW RSI(2) LINE AT 90
DRAW BOLLINGER BANDS(10,2)

DRAW ZSCORE20 LINE AT 0

CHART-TIME IS 3 MONTHS
]




AND HERE IS THE COMPLETE CODE FOR PANGOLIN W - most of the code, specifically the risk control elements and position sizing, are identical so rather than walk through it line by line here is the full filter. Note that the limit entry strategy is the same, but the exit occurs at an RSI(2) of 85 rather than 90.

Fetcher[
S&P 500

COUNT(ROC(9,1) BELOW -1,2) ABOVE 1
ROC(50,1) ABOVE 5
CLOSE ABOVE MA(200)
RSI(2) BELOW 15

SET{2ATR, 2 * ATR(20)}
SET{ACCOUNTSIZE,25000}
SET{RISKLEVEL, ACCOUNTSIZE*0.005}
SET{LIMITENTRY, MIN(CLOSE,REVERSERSI(2,5))}
SET{SHARESTOBUY1, RISKLEVEL / 2ATR}
SET{SHARESTOBUY, ROUND(SHARESTOBUY1,0)}
SET{POSITIONAMT, LIMITENTRY * SHARESTOBUY}
SET{STOPLOSS, LIMITENTRY - 2ATR}
SET{DIFF, LIMITENTRY - STOPLOSS}
SET{REWARD1, REVERSERSI(2,85) - LIMITENTRY}
SET{R_R, REWARD1 / RISKLEVEL}

ADD COLUMN RSI(2)
ADD COLUMN ROC(9,1) {ROC(9)}
ADD COLUMN ROC(50,1) {ROC(50)}
ADD COLUMN SEPARATOR
ADD COLUMN SHARESTOBUY {SHARES TO BUY}
ADD COLUMN LIMITENTRY {LIMIT ENTRY}
ADD COLUMN REVERSERSI(2,85) {PROFIT TARGET}
ADD COLUMN STOPLOSS {STOP LOSS}
ADD COLUMN R_R {REWARD-TO-RISK}
ADD COLUMN POSITIONAMT {POSITION SIZE IN DOLLARS}

DRAW PRICE LINE AT LIMITENTRY
DRAW PRICE LINE AT REVERSERSI(2,85)
DRAW RSI(2) LINE AT 5
DRAW RSI(2) LINE AT 85
DO NOT DRAW ROC(9,1)
DO NOT DRAW ROC(50,1)
SORT ON COLUMN 5 DESCENDING
CHART-TIME IS 3 MONTHS
]



Enjoy.

duke56468
683 posts
msg #122433
Ignore duke56468
modified
12/31/2014 11:36:46 AM

Thanks for sharing Kevin. Although you never truly left, we're glad to have you back.

Mactheriverrat
3,157 posts
msg #122438
Ignore Mactheriverrat
modified
12/31/2014 10:49:29 PM

Also glad to see you are still around Kevin. I still use your weekly Macd (2,3) on some of my filters

sohailmithani
192 posts
msg #122441
Ignore sohailmithani
1/1/2015 1:11:10 PM

That is very generous of you Kevin.

However, I noticed that trades run through this filter do not match with your C2 trades list. Anything I am missing.
Also, any idea how to back test this filter on SF.

Thanks again

sohailmithani
192 posts
msg #122442
Ignore sohailmithani
1/1/2015 1:41:10 PM

Also, Kevin it would be helpful to know how many trades one enters per day (max) to get the best out of it.

Thanks

Kevin_in_GA
4,599 posts
msg #122445
Ignore Kevin_in_GA
1/1/2015 5:02:41 PM

The trades are the same, since this is the source for all of my trades since the inception of Pangolin Z. I would periodically use lowest RSI or highest R/R to make selections, but all trade will be found if one looks.

The system was optimized on 5-10 trades. Either work well, but when using the Van Tharp position sizing you will find that not all of your available funds are in play. In that case you can increase the number of trades, but only from what the filter returns.

evo34
82 posts
msg #122448
Ignore evo34
1/1/2015 6:42:13 PM

Thanks for posting, Kevin. Were these tested against a survivorship-bias free dataset? If so, any meaningful difference in performance vs. using only current S&P 500 components?

Secondly, just wondering if you have tested hedging your trades with a short position in SPY? I.e., would it be worth it to hedge your notional long positions with X% short SPY, in terms of maximizing Sharpe ratio? Or would transaction costs likely overwhelm any advantage?

sohailmithani
192 posts
msg #122449
Ignore sohailmithani
modified
1/1/2015 6:56:53 PM

Thanks again Kevin for the explanation. I still do not get all trades from filter to compare it 100% with your C2 data. May be there were some discretionary trades taken by you.

Also, any guidance on how to back test this filter will be great.

Thanks again

fotchstecker
304 posts
msg #122452
Ignore fotchstecker
1/3/2015 11:25:29 AM

Very generous. Thank you, Kevin.

evo34
82 posts
msg #122457
Ignore evo34
1/4/2015 2:43:56 AM

FYI -- the reward-to-risk ratio calc. is different in the two filters. It looks like the code in Pangolin W may be in error (it's using the raw diff. in share price).

StockFetcher Forums · Filter Exchange · PANGOLIN Z AND PANGOLIN W - FULL SYSTEM CODE<< 1 2 3 4 5 ... 9 >>Post Follow-up

*** Disclaimer *** StockFetcher.com does not endorse or suggest any of the securities which are returned in any of the searches or filters. They are provided purely for informational and research purposes. StockFetcher.com does not recommend particular securities. StockFetcher.com, Vestyl Software, L.L.C. and involved content providers shall not be liable for any errors or delays in the content, or for any actions taken based on the content.


Copyright 2022 - Vestyl Software L.L.C.Terms of Service | License | Questions or comments? Contact Us
EOD Data sources: DDFPlus & CSI Data Quotes delayed during active market hours. Delay times are at least 15 mins for NASDAQ, 20 mins for NYSE and Amex. Delayed intraday data provided by DDFPlus


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.