FRAMA Part IV: Continuing the Long/Short Filter Search

[This article was first published on QuantStrat TradeR » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

This post examines an n-day median filter for two desirable properties: robustness to outliers and an inherent trend-confirming lag. While this is an incomplete filter (or maybe even inferior), it offers some key insights into improving the trading system.

The strategy will be thus:

First and foremost, this will be a short-only strategy, due to the long bias within the sample period, so the stress-test of the system will be to attempt to capture the non-dominant trend (and only when appropriate).

Here’s the strategy: we will continue to use the same 126 day FRAMA with the fast constant set at 4, and a slow constant at 300 (that is, it can oscillate anywhere between an EMA4 and EMA300). We will only enter into a short position when this indicator is descending, below the 126-day median of the price action, and when the price action is lower than this indicator (usually this means a cross, not in all cases though). We will exit when the price action rises back above the indicator.

Here’s the strategy in R code:

require(DSTrading)
require(IKTrading)
require(quantstrat)
require(PerformanceAnalytics)

initDate="1990-01-01"
from="2003-01-01"
to="2010-12-31"
options(width=70)

#to rerun the strategy, rerun everything below this line
source("demoData.R") #contains all of the data-related boilerplate.

#trade sizing and initial equity settings
tradeSize <- 10000
initEq <- tradeSize*length(symbols)

strategy.st <- portfolio.st <- account.st <- "FRAMA_III"
rm.strat(portfolio.st)
rm.strat(strategy.st)
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, currency='USD',initEq=initEq)
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=TRUE)

#parameters

FC=4
SC=300
n=126
triggerLag=1

period=10
pctATR=.02

#indicators 

add.indicator(strategy.st, name="FRAMA",
              arguments=list(HLC=quote(HLC(mktdata)), n=n, 
                             SC=SC, FC=FC, triggerLag=triggerLag),
              label="primary")

add.indicator(strategy.st, name="runMedian",
              arguments=list(x=quote(Cl(mktdata)), n=n),
              label="confirmatory")

add.indicator(strategy.st, name="lagATR", 
              arguments=list(HLC=quote(HLC(mktdata)), n=period), 
              label="atrX")

# #long signals
# 
# add.signal(strategy.st, name="sigComparison",
#            arguments=list(columns=c("FRAMA.primary", "X1.confirmatory"), 
#                           relationship="gte"),
#            label="FRAMAgteMedian")
# 
# add.signal(strategy.st, name="sigComparison",
#            arguments=list(columns=c("FRAMA.primary", "trigger.primary"), 
#                           relationship="gte"),
#            label="FRAMArising")
# 
# add.signal(strategy.st, name="sigComparison",
#            arguments=list(columns=c("Close", "FRAMA.primary"), 
#                           relationship="gte"),
#            label="ClGtFRAMA")
# 
# add.signal(strategy.st, name="sigAND",
#            arguments=list(columns=c("FRAMAgteMedian", 
#                                     "FRAMArising", "ClGtFRAMA"), 
#                           cross=TRUE),
#            label="longEntry")
# 
# add.signal(strategy.st, name="sigCrossover",
#            arguments=list(columns=c("Close", "FRAMA.primary"), 
#                           relationship="lt"),
#            label="longExit")
# 
# #long rules
# 
# add.rule(strategy.st, name="ruleSignal", 
#          arguments=list(sigcol="longEntry", sigval=TRUE, ordertype="market", 
#                         orderside="long", replace=FALSE, prefer="Open", osFUN=osDollarATR,
#                         tradeSize=tradeSize, pctATR=pctATR, atrMod="X"), 
#          type="enter", path.dep=TRUE)
# 
# add.rule(strategy.st, name="ruleSignal", 
#          arguments=list(sigcol="longExit", sigval=TRUE, orderqty="all", ordertype="market", 
#                         orderside="long", replace=FALSE, prefer="Open"), 
#          type="exit", path.dep=TRUE)

#short signals

add.signal(strategy.st, name="sigComparison",
           arguments=list(columns=c("FRAMA.primary", "X1.confirmatory"), 
                          relationship="lt"),
           label="FRAMAltMedian")

add.signal(strategy.st, name="sigComparison",
           arguments=list(columns=c("FRAMA.primary", "trigger.primary"), 
                          relationship="lt"),
           label="FRAMAfalling")

add.signal(strategy.st, name="sigComparison",
           arguments=list(columns=c("Close", "FRAMA.primary"), 
                          relationship="lt"),
           label="ClLtFRAMA")

add.signal(strategy.st, name="sigAND",
           arguments=list(columns=c("FRAMAltMedian", 
                                    "FRAMAfalling", "ClLtFRAMA"), 
                          cross=TRUE),
           label="shortEntry")

add.signal(strategy.st, name="sigCrossover",
           arguments=list(columns=c("Close", "FRAMA.primary"), 
                          relationship="gt"),
           label="shortExit")

#short rules

add.rule(strategy.st, name="ruleSignal", 
         arguments=list(sigcol="shortEntry", sigval=TRUE, ordertype="market", 
                        orderside="short", replace=FALSE, prefer="Open", osFUN=osDollarATR,
                        tradeSize=-tradeSize, pctATR=pctATR, atrMod="X"), 
         type="enter", path.dep=TRUE)

add.rule(strategy.st, name="ruleSignal", 
         arguments=list(sigcol="shortExit", sigval=TRUE, orderqty="all", ordertype="market", 
                        orderside="short", replace=FALSE, prefer="Open"), 
         type="exit", path.dep=TRUE)



#apply strategy
t1 <- Sys.time()
out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st)
t2 <- Sys.time()
print(t2-t1)


#set up analytics
updatePortf(portfolio.st)
dateRange <- time(getPortfolio(portfolio.st)$summary)[-1]
updateAcct(portfolio.st,dateRange)
updateEndEq(account.st)

The results aren’t pretty, meaning that the filter is still incomplete. Here are the trade stats:

                        EFA      EPP      EWA      EWC      EWG
Num.Txns              90.00    68.00    85.00    66.00    90.00
Num.Trades            44.00    34.00    41.00    33.00    45.00
Net.Trading.PL     -2030.68   -25.54 -1485.82 -2283.03  -356.83
Avg.Trade.PL         -46.15    -0.75   -36.24   -69.18    -7.93
Med.Trade.PL        -103.99   -44.95   -77.27  -100.40   -69.91
Largest.Winner      1238.56  1656.56  1106.59  2195.51  3197.29
Largest.Loser       -661.04  -786.27  -548.06  -823.55  -783.65
Gross.Profits       4336.92  4455.45  3246.48  3566.35  5948.76
Gross.Losses       -6367.61 -4480.99 -4732.30 -5849.38 -6305.59
Std.Dev.Trade.PL     364.75   419.42   288.36   487.05   557.98
Percent.Positive      29.55    32.35    43.90    24.24    37.78
Percent.Negative      70.45    67.65    56.10    75.76    62.22
Profit.Factor          0.68     0.99     0.69     0.61     0.94
Avg.Win.Trade        333.61   405.04   180.36   445.79   349.93
Med.Win.Trade         57.09   238.60    66.34   124.31   101.88
Avg.Losing.Trade    -205.41  -194.83  -205.75  -233.98  -225.20
Med.Losing.Trade    -156.80  -122.45  -170.49  -166.84  -184.70
Avg.Daily.PL         -46.15    -0.75   -36.24   -69.18    -7.93
Med.Daily.PL        -103.99   -44.95   -77.27  -100.40   -69.91
Std.Dev.Daily.PL     364.75   419.42   288.36   487.05   557.98
Ann.Sharpe            -2.01    -0.03    -2.00    -2.25    -0.23
Max.Drawdown       -5089.55 -3095.58 -3609.64 -4915.76 -4222.60
Profit.To.Max.Draw    -0.40    -0.01    -0.41    -0.46    -0.08
Avg.WinLoss.Ratio      1.62     2.08     0.88     1.91     1.55
Med.WinLoss.Ratio      0.36     1.95     0.39     0.75     0.55
Max.Equity           146.74  1473.19   834.54    78.43  1467.12
Min.Equity         -4942.81 -2562.72 -2775.10 -4837.32 -3960.49
End.Equity         -2030.68   -25.54 -1485.82 -2283.03  -356.83

                        EWH      EWJ      EWS      EWT      EWU
Num.Txns              74.00   102.00    72.00    66.00    72.00
Num.Trades            36.00    51.00    35.00    33.00    36.00
Net.Trading.PL       596.16 -1493.76   982.93  1354.40   439.00
Avg.Trade.PL          16.56   -29.29    28.08    41.04    12.19
Med.Trade.PL         -54.45   -89.63   -52.85   -40.22   -56.50
Largest.Winner      3436.43  1076.25  1165.10  1980.68  1680.33
Largest.Loser       -544.78  -781.15  -429.64  -441.47  -468.28
Gross.Profits       4519.53  5681.81  4763.28  4317.26  5105.73
Gross.Losses       -3923.37 -7175.57 -3780.35 -2962.87 -4666.73
Std.Dev.Trade.PL     610.29   368.61   353.59   408.77   415.23
Percent.Positive      38.89    37.25    37.14    42.42    33.33
Percent.Negative      61.11    62.75    62.86    57.58    66.67
Profit.Factor          1.15     0.79     1.26     1.46     1.09
Avg.Win.Trade        322.82   299.04   366.41   308.38   425.48
Med.Win.Trade         79.88    99.19   267.75   115.47   399.34
Avg.Losing.Trade    -178.33  -224.24  -171.83  -155.94  -194.45
Med.Losing.Trade    -137.71  -175.69  -141.06   -95.88  -180.13
Avg.Daily.PL          16.56   -29.29    28.08    41.04    12.19
Med.Daily.PL         -54.45   -89.63   -52.85   -40.22   -56.50
Std.Dev.Daily.PL     610.29   368.61   353.59   408.77   415.23
Ann.Sharpe             0.43    -1.26     1.26     1.59     0.47
Max.Drawdown       -2390.89 -2994.16 -1689.63 -2113.93 -3192.52
Profit.To.Max.Draw     0.25    -0.50     0.58     0.64     0.14
Avg.WinLoss.Ratio      1.81     1.33     2.13     1.98     2.19
Med.WinLoss.Ratio      0.58     0.56     1.90     1.20     2.22
Max.Equity          2534.61  1380.90  1938.04  2065.70  1845.45
Min.Equity         -2131.17 -2540.03 -1265.23 -1501.15 -3192.52
End.Equity           596.16 -1493.76   982.93  1354.40   439.00

                        EWY      EWZ      EZU      IEF      IGE
Num.Txns              68.00    80.00    96.00    63.00    56.00
Num.Trades            34.00    40.00    48.00    32.00    28.00
Net.Trading.PL      1359.59 -2763.77  -178.24 -5286.17  -588.44
Avg.Trade.PL          39.99   -69.09    -3.71  -165.19   -21.02
Med.Trade.PL          19.52  -103.71   -73.53  -253.57   -87.68
Largest.Winner      1799.34  2495.03  1423.73   908.54  2146.42
Largest.Loser       -467.07  -496.73  -847.67  -758.78  -466.57
Gross.Profits       4729.27  2790.33  5960.68  2309.18  2757.36
Gross.Losses       -3369.68 -5554.10 -6138.92 -7595.36 -3345.80
Std.Dev.Trade.PL     414.55   440.16   402.00   349.52   456.89
Percent.Positive      55.88    15.00    33.33    25.00    25.00
Percent.Negative      44.12    85.00    66.67    75.00    75.00
Profit.Factor          1.40     0.50     0.97     0.30     0.82
Avg.Win.Trade        248.91   465.05   372.54   288.65   393.91
Med.Win.Trade         58.75    43.02    67.59   156.68    43.03
Avg.Losing.Trade    -224.65  -163.36  -191.84  -316.47  -159.32
Med.Losing.Trade    -217.23  -110.98  -139.29  -284.87  -115.98
Avg.Daily.PL          39.99   -69.09    -3.71  -192.64   -21.02
Med.Daily.PL          19.52  -103.71   -73.53  -260.53   -87.68
Std.Dev.Daily.PL     414.55   440.16   402.00   318.33   456.89
Ann.Sharpe             1.53    -2.49    -0.15    -9.61    -0.73
Max.Drawdown       -2237.74 -3903.71 -3510.08 -6682.82 -2836.80
Profit.To.Max.Draw     0.61    -0.71    -0.05    -0.79    -0.21
Avg.WinLoss.Ratio      1.11     2.85     1.94     0.91     2.47
Med.WinLoss.Ratio      0.27     0.39     0.49     0.55     0.37
Max.Equity          3532.28   836.88  1270.40   669.24   709.44
Min.Equity          -790.83 -3066.84 -3222.22 -6013.57 -2127.36
End.Equity          1359.59 -2763.77  -178.24 -5286.17  -588.44

                        IYR      IYZ      LQD      RWR      SHY
Num.Txns              96.00   108.00    63.00    98.00    51.00
Num.Trades            48.00    54.00    31.00    49.00    25.00
Net.Trading.PL     -3444.89 -2032.70  1532.27 -3740.29 -4049.16
Avg.Trade.PL         -71.77   -37.64    49.43   -76.33  -161.97
Med.Trade.PL        -129.99   -83.00   -84.44  -114.84  -141.20
Largest.Winner      1714.13  2673.04  2693.04  1455.78    86.02
Largest.Loser       -745.50  -463.08  -480.73  -578.29  -644.17
Gross.Profits       4652.33  4978.26  5114.62  3534.95   365.46
Gross.Losses       -8097.22 -7010.97 -3582.35 -7275.24 -4414.63
Std.Dev.Trade.PL     405.93   479.46   604.30   341.37   195.72
Percent.Positive      22.92    22.22    35.48    16.33    28.00
Percent.Negative      77.08    77.78    64.52    83.67    72.00
Profit.Factor          0.57     0.71     1.43     0.49     0.08
Avg.Win.Trade        422.94   414.86   464.97   441.87    52.21
Med.Win.Trade        110.81    29.28   139.76   188.82    44.33
Avg.Losing.Trade    -218.84  -166.93  -179.12  -177.44  -245.26
Med.Losing.Trade    -182.73  -134.02  -129.79  -138.78  -232.61
Avg.Daily.PL         -71.77   -37.64    45.47   -76.33  -162.83
Med.Daily.PL        -129.99   -83.00   -86.18  -114.84  -144.12
Std.Dev.Daily.PL     405.93   479.46   614.22   341.37   199.88
Ann.Sharpe            -2.81    -1.25     1.18    -3.55   -12.93
Max.Drawdown       -3857.85 -5575.45 -2876.51 -4695.60 -4049.16
Profit.To.Max.Draw    -0.89    -0.36     0.53    -0.80    -1.00
Avg.WinLoss.Ratio      1.93     2.49     2.60     2.49     0.21
Med.WinLoss.Ratio      0.61     0.22     1.08     1.36     0.19
Max.Equity           260.07   118.92  3375.06   302.96     0.00
Min.Equity         -3597.77 -5456.52 -2138.62 -4392.65 -4049.16
End.Equity         -3444.89 -2032.70  1532.27 -3740.29 -4049.16

                        TLT      XLB      XLE      XLF      XLI
Num.Txns              85.00   104.00    50.00   120.00    92.00
Num.Trades            43.00    51.00    25.00    60.00    46.00
Net.Trading.PL     -4037.97 -5591.16  -308.15 -3036.79 -2136.85
Avg.Trade.PL         -93.91  -109.63   -12.33   -50.61   -46.45
Med.Trade.PL        -133.03  -138.47   -96.47   -79.48  -108.98
Largest.Winner      1425.91  1831.45  1828.51  1058.03  1218.87
Largest.Loser       -543.28  -707.20  -430.13  -711.69  -632.77
Gross.Profits       3355.40  3130.31  2472.08  5282.27  4597.82
Gross.Losses       -7393.37 -8721.48 -2780.24 -8319.05 -6734.68
Std.Dev.Trade.PL     338.88   345.20   420.71   309.84   342.80
Percent.Positive      25.58    25.49    20.00    30.00    23.91
Percent.Negative      74.42    74.51    80.00    70.00    76.09
Profit.Factor          0.45     0.36     0.89     0.63     0.68
Avg.Win.Trade        305.04   240.79   494.42   293.46   417.98
Med.Win.Trade        168.50    83.98    33.87   135.46   294.74
Avg.Losing.Trade    -231.04  -229.51  -139.01  -198.07  -192.42
Med.Losing.Trade    -197.38  -207.82  -120.99  -171.67  -149.06
Avg.Daily.PL        -101.44  -109.63   -12.33   -50.61   -46.45
Med.Daily.PL        -140.48  -138.47   -96.47   -79.48  -108.98
Std.Dev.Daily.PL     339.33   345.20   420.71   309.84   342.80
Ann.Sharpe            -4.75    -5.04    -0.47    -2.59    -2.15
Max.Drawdown       -4926.34 -6711.79 -1938.05 -3451.10 -4068.90
Profit.To.Max.Draw    -0.82    -0.83    -0.16    -0.88    -0.53
Avg.WinLoss.Ratio      1.32     1.05     3.56     1.48     2.17
Med.WinLoss.Ratio      0.85     0.40     0.28     0.79     1.98
Max.Equity           459.78     0.00  1298.51   414.31     0.00
Min.Equity         -4466.56 -6711.79 -1329.01 -3036.79 -4068.90
End.Equity         -4037.97 -5591.16  -308.15 -3036.79 -2136.85

                        XLK      XLP      XLU      XLV      XLY
Num.Txns              86.00    92.00    82.00    94.00    82.00
Num.Trades            43.00    45.00    40.00    47.00    40.00
Net.Trading.PL     -1205.62 -4427.34 -3490.76 -4291.56  -230.80
Avg.Trade.PL         -28.04   -98.39   -87.27   -91.31    -5.77
Med.Trade.PL        -101.30  -153.01   -93.87   -98.69  -140.01
Largest.Winner      2403.16  1008.09  1805.03   842.35  2090.68
Largest.Loser       -806.29  -460.10  -462.68  -554.57  -698.45
Gross.Profits       4984.72  2839.42  2493.63  2959.31  6253.33
Gross.Losses       -6190.34 -7266.76 -5984.39 -7250.87 -6484.14
Std.Dev.Trade.PL     464.22   294.41   350.37   280.87   495.21
Percent.Positive      30.23    15.56    20.00    19.15    30.00
Percent.Negative      69.77    84.44    80.00    80.85    70.00
Profit.Factor          0.81     0.39     0.42     0.41     0.96
Avg.Win.Trade        383.44   405.63   311.70   328.81   521.11
Med.Win.Trade        191.31   116.12    61.87   266.16   307.13
Avg.Losing.Trade    -206.34  -191.23  -187.01  -190.81  -231.58
Med.Losing.Trade    -188.49  -191.04  -156.33  -161.51  -171.21
Avg.Daily.PL         -28.04   -98.39   -87.27   -91.31    -5.77
Med.Daily.PL        -101.30  -153.01   -93.87   -98.69  -140.01
Std.Dev.Daily.PL     464.22   294.41   350.37   280.87   495.21
Ann.Sharpe            -0.96    -5.30    -3.95    -5.16    -0.18
Max.Drawdown       -3448.99 -5384.93 -3540.13 -5186.60 -3964.07
Profit.To.Max.Draw    -0.35    -0.82    -0.99    -0.83    -0.06
Avg.WinLoss.Ratio      1.86     2.12     1.67     1.72     2.25
Med.WinLoss.Ratio      1.01     0.61     0.40     1.65     1.79
Max.Equity           646.11   651.59     0.00   895.04  2960.96
Min.Equity         -3003.57 -4733.34 -3540.13 -4291.56 -1003.11
End.Equity         -1205.62 -4427.34 -3490.76 -4291.56  -230.80

At this point, for the sake of brevity, I’ll leave off the equity curves and portfolio statistics (they’ll obviously be bad). However, let’s look at some images of what exactly is going on with individual trades.

Here is the full-backtest equity curve and corresponding indicators for XLP. The FRAMA is in purple, with the 126-day median in orange, along with the 10-day ATR (lagged by a day) on the bottom.

And here we can immediately see certain properties:

1) ATR order-sizing is not a be-all, end-all type of order. It was created for one purpose, which is to equalize risk across instruments (the original idea of which, I defer to Andreas Clenow’s article). However, that is only a base from which to begin, using other scaled order-sizing procedures which can attempt to quantify the confidence in any particular trade. As it currently stands, for short strategies in equities, the best opportunities happen in the depths of rapid falling price action, during which ATR will rise. One may consider augmenting the ATR order sizing function in order to accomplish this task (or merely apply leverage at the proper time, through modifying the pctATR parameter).

2) While the running median certainly has value as a filter to keep out obviously brainless trades (E.G. in the middle of an uptrend), once the FRAMA crosses the median, anything can happen, as the only logic is that the current FRAMA is just slightly lower than the previous day’s. This may mean that the running median itself is still rising, or that the FRAMA is effectively flat, and what is being traded on is purely noise. And furthermore, with ATR order sizing amplifying the consequences of that noise, this edge case can have disastrous consequences on an equity curve.

Here’s a zoom in on 2005, where we see a pretty severe drawdown (chart time series recolored for clarity).

As can be seen, even though the FRAMA seems to be slightly rising, a price crossing when the FRAMA is lower than the previous day by even an invisibly small amount (compare the purple–the FRAMA, to the red–the same quantity lagged a day) is enough to trigger a trade that will buy a sizable number of shares, even when the volatility is too small to justify such a trade. Essentially, most of the losses in this trading system arise as a result of trading during these flat periods during which the system attempts to force action.

This pattern repeats itself. Here is the equity curve for XLB.

Again, aside from maybe a bad trade in the end thanks to any trade being taken once all three conditions line up (decreasing FRAMA, FRAMA lower than median, price lower than FRAMA) too late due to a flat FRAMA/median relationship, most of the losers seem to be trades made during very flat and calm market action, even when the running median may be going in the opposite direction of the FRAMA, during which the ATR order-sizing function tried to force action. A second filter that serves to catch these edge-case situations (or maybe a filter that replaces the running median entirely) will be investigated in the future.

So, to recap this post:

The running median filter is an intrinsically lagging but robust indicator, chosen deliberately for these two properties. It is able to filter out trades that obviously go against the trend. However, due to some edge cases, there were still a great deal of losses that were incurred, which drown out the one good shorting opportunity over this sample period. This is an issue that needs addressing.

Thanks for reading.


To leave a comment for the author, please follow the link and comment on their blog: QuantStrat TradeR » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)