-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathSingle asset SMA.R
executable file
·264 lines (216 loc) · 9.04 KB
/
Single asset SMA.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
###############################
### blotter package example ###
###############################
# Jeremy Siegel and Mebane Faber trend following strategy using a 200-day simple moving average
# from "A Quantitative Approach to Tactical Asset Allocation."
# adapted from script longtrend.R in package blotter
# this demo uses monthly SP500 data from Yahoo Finance, instead of total return data.
# Load required libraries
require(quantmod)
require(TTR)
require(blotter)
# set TZ
Sys.setenv(TZ="UTC")
# load data (quantmod)
getSymbols('^GSPC', src='yahoo', index.class=c("POSIXt", "POSIXct"), from='1998-01-01')
GSPC.daily <- GSPC
##############################################
### version slightly modified longtrend.R ###
##############################################
# this version is path-dependent because number of shares traded
# is scaled to the time-dependent equity
# xts objects are stored in the global environment
# portfolio and account objects are stored in .blotter environment
# currency and trading instrument objects are stored in the .instrument environment
# remove objects in case demo was run previously
try(rm("account.longtrend", "portfolio.longtrend", pos=.blotter), silent=TRUE)
try(rm("ltaccount", "ltportfolio", "ClosePrice", "CurrentDate", "equity", "date.bar", "initDate", "initEq", "Posn", "UnitSize"), silent=TRUE)
# Set initial values
initDate <- '1997-12-31'
initEq <- 10000
# define instruments (FinancialInstrument)
print("Loading data")
currency("USD")
stock("GSPC", currency="USD", multiplier=1)
# create monthly data
GSPC <- to.monthly(GSPC.daily, indexAt='endof', drop.time=FALSE)
# add SMA indicator column (TTR)
print("Setting up indicators")
ma.window <- 8
GSPC$indicator <- SMA(GSPC[, grep('Adjusted', colnames(GSPC))], ma.window)
print("Initializing portfolio and account structure")
# assign portfolio and account names
ltportfolio <- 'longtrend'
ltaccount <- 'longtrend'
# create portfolio and account objects (blotter)
initPortf(ltportfolio, 'GSPC', initDate=initDate)
initAcct(ltaccount, portfolios='longtrend', initDate=initDate, initEq=initEq)
# initialize position to some small size (blotter)
addTxn(ltportfolio, Symbol='GSPC', TxnDate=time(GSPC)[ma.window], TxnPrice=1, TxnQty=1, TxnFees=0, verbose=TRUE)
# main loop to create trades
for (date.bar in ma.window:nrow(GSPC)) {
# browser()
CurrentDate <- time(GSPC)[date.bar]
# get last equity (blotter)
equity <- getEndEq(ltaccount, CurrentDate)
# get value of 'Adjusted' price column
ClosePrice <- as.numeric(Ad(GSPC[date.bar, ]))
# calc number of shares
UnitSize <- as.numeric(trunc(equity/ClosePrice))
# get last position (blotter)
Posn <- getPosQty(ltportfolio, Symbol='GSPC', Date=CurrentDate)
# perform trade if current position is in opposite direction to indicator
UnitSize <- -sign(Posn)*UnitSize
flip.indic <- (Posn*(as.numeric(Ad(GSPC[date.bar, ])) - as.numeric(GSPC[date.bar, 'indicator']))) < 0
cat('.')
# cat(paste('.', Posn, UnitSize, '\n'))
# Flip position if indicator is opposite to current position
if (flip.indic) {
cat('\n')
# store trade in blotter
addTxn(ltportfolio, Symbol='GSPC', TxnDate=CurrentDate, TxnPrice=ClosePrice, TxnQty=UnitSize-Posn, TxnFees=0, verbose=TRUE)
} # end if
# Calculate P&L and resulting equity (blotter)
updatePortf(ltportfolio, Dates=CurrentDate)
updateAcct(ltaccount, Dates=CurrentDate)
updateEndEq(ltaccount, Dates=CurrentDate)
} # End dates loop
cat('\n')
##############################################
### end slightly modified version ###
##############################################
##############################################
### longtrend.R faster simplified version ###
##############################################
# this version trades a fixed number of shares, so it's path-independent and faster
# it doesn't Calculate equity amount in account object
# xts objects are stored in the global environment
# portfolio and account objects are stored in .blotter environment
# currency and trading instrument objects are stored in the .instrument environment
# remove objects in case demo was run previously
try(rm("account.longtrend", "portfolio.longtrend", pos=.blotter), silent=TRUE)
try(rm("ltaccount", "ltportfolio", "ClosePrice", "CurrentDate", "date.bar", "initDate", "initEq", "posn.indic", "flip.indic", "UnitSize"), silent=TRUE)
# Set initial values
initDate <- '1997-12-31'
initEq <- 10000
# define instruments (FinancialInstrument)
print("Loading data")
currency("USD")
stock("GSPC", currency="USD", multiplier=1)
# create monthly data
GSPC <- to.monthly(GSPC.daily, indexAt='endof', drop.time=FALSE)
# add SMA indicator column (TTR)
print("Setting up indicators")
ma.window <- 8
GSPC$indicator <- SMA(Ad(GSPC), ma.window)
GSPC[1:(ma.window-1), 'indicator'] <- GSPC[ma.window, 'indicator']
print("Initializing portfolio and account structure")
### assign portfolio and account names
ltportfolio <- 'longtrend'
ltaccount <- 'longtrend'
# create portfolio and account objects (blotter)
initPortf(ltportfolio, 'GSPC', initDate=initDate)
initAcct(ltaccount, portfolios='longtrend', initDate=initDate, initEq=initEq)
### initialize all the variables
# trade one unit of stock
UnitSize <- 1
# get time index
index.GSPC <- index(GSPC)
# initialize posn.indic and flip.indic
posn.indic <- sign(Ad(GSPC) - GSPC[, 'indicator'])
flip.indic <- lag(posn.indic)*posn.indic < 0
flip.indic[1] <- FALSE
posn.indic <- as.numeric(posn.indic)
# initialize position to UnitSize (blotter)
addTxn(ltportfolio, Symbol='GSPC', TxnDate=index.GSPC[1], TxnPrice=as.numeric(Ad(GSPC[1, ])), TxnQty=posn.indic[1]*UnitSize, TxnFees=0, verbose=TRUE)
# main loop to create trades
for (date.bar in 2:nrow(GSPC)) {
# browser()
cat('.')
CurrentDate <- index.GSPC[date.bar]
# get value of 'Adjusted' price column
ClosePrice <- as.numeric(Ad(GSPC[date.bar, ]))
# Flip position if indicator is opposite to current position
if (flip.indic[date.bar]) {
cat('\n')
# store trade in blotter
addTxn(ltportfolio, Symbol='GSPC', TxnDate=CurrentDate, TxnPrice=ClosePrice, TxnQty=2*posn.indic[date.bar]*UnitSize, TxnFees=0, verbose=TRUE)
} # end if
# Calculate P&L and resulting equity (blotter)
updatePortf(ltportfolio, Dates=CurrentDate)
} # End dates loop
cat('\n')
##############################################
### end simplified version ###
##############################################
##############################################
### performance charts and statistics ###
##############################################
# chart strategy (blotter)
chart.Posn(ltportfolio, Symbol='GSPC', Dates='1998::')
# Add MA (quantmod)
plot(add_SMA(n=ma.window, col='darkgreen', on=1))
# optional copy the results into the local environment (blotter)
print("Retrieving resulting portfolio and account")
ltportfolio <- getPortfolio("longtrend")
ltaccount <- getAccount("longtrend")
# get transaction summary (blotter)
getTxns(Portfolio="longtrend", Symbol="GSPC")
# get strategy statistics
tradeStats(Portfolio=ltportfolio)
trade.stats <- tradeStats(Portfolio=ltportfolio)
# arrange strategy statistics
# trade statistics
tab.trades <- cbind(
c("Trades","Win Percent","Loss Percent","W/L Ratio"),
c(trade.stats[,"Num.Trades"],trade.stats[,c("Percent.Positive","Percent.Negative")],
trade.stats[,"Percent.Positive"]/trade.stats[,"Percent.Negative"])
)
# profit statistics
tab.profit <- cbind(
c("Net Profit","Gross Profits","Gross Losses","Profit Factor"),
c(trade.stats[,c("Net.Trading.PL","Gross.Profits","Gross.Losses",
"Profit.Factor")])
)
# averages
tab.wins <- cbind(
c("Avg Trade","Avg Win","Avg Loss","Avg W/L Ratio"),
c(trade.stats[,c("Avg.Trade.PL","Avg.Win.Trade","Avg.Losing.Trade",
"Avg.WinLoss.Ratio")])
)
# combine statistics (needs work)
trade.stats.tab <- data.frame(tab.trades,tab.profit,tab.wins)
# PerformanceAnalytics statistics
ts.rets <- PortfReturns(Account=ltportfolio)
rownames(ts.rets) <- NULL
tail(ts.rets)
charts.PerformanceSummary(ts.rets, colorset=bluefocus)
table.Arbitrary(ts.rets)
tab.perf <- table.Arbitrary(ts.rets,
metrics=c(
"Return.cumulative",
"Return.annualized",
"SharpeRatio.annualized",
"CalmarRatio"),
metricsNames=c(
"Cumulative Return",
"Annualized Return",
"Annualized Sharpe Ratio",
"Calmar Ratio"))
tab.perf
tab.risk <- table.Arbitrary(ts.rets,
metrics=c(
"StdDev.annualized",
"maxDrawdown",
"VaR",
"ES"),
metricsNames=c(
"Annualized StdDev",
"Max DrawDown",
"Value-at-Risk",
"Conditional VaR"))
tab.risk
performance.stats.tab <- data.frame(
rownames(tab.perf),tab.perf[,1],
rownames(tab.risk),tab.risk[,1])
performance.stats.tab