Skip to content

Instantly share code, notes, and snippets.

@thertrader
Created March 12, 2014 15:39
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 31 You must be signed in to fork a gist
  • Save thertrader/9509411 to your computer and use it in GitHub Desktop.
Save thertrader/9509411 to your computer and use it in GitHub Desktop.
Using Genetic Algorithms in Quantitative Trading
############################################################
## Using Genetic Algorithms in Quantitative Trading
##
## thertrader@gmail.com - Mar 2014
############################################################
library(PerformanceAnalytics)
library(rgenoud)
library(quantmod)
library(TTR)
###############
outputPath <- "your_path"
theInstrument <- "SPY"
data <- getSymbols(Symbols = theInstrument,
src = "yahoo",
from = "2000-01-01",
auto.assign = FALSE)
colnames(data) <- c("open","high","low","close","volume","adj.")
###############
fitnessFunction <- function(xx=c(1,1,1,1)){
print(xx)
rtn <- ROC(data[,"close"],n=1)
rsi <- RSI(data[,"close"],n=xx[1],maType="SMA")
smas <- SMA(data[,"close"],n=xx[3])
smal <- SMA(data[,"close"],n=xx[4])
aa <- cbind(data[,"close"],rtn,rsi,smas,smal)
colnames(aa) <- c("close","rtn","rsi","smas","smal")
isData <- aa[index(aa) < "2011-01-01"]
posBuySignal <- which(isData[,"rsi"] <= (1 - xx[2]) & isData[,"smas"] > isData[,"smal"]) + 1
if (length(posBuySignal) == 0)
posBuySignal <- NULL
posSellSignal <- which(isData[,"rsi"] > xx[2] & isData[,"smas"] < isData[,"smal"]) + 1
if (length(posSellSignal) == 0)
posSellSignal <- NULL
allSignals <- c(posBuySignal,posSellSignal)
allSignals <- allSignals[which(allSignals <= nrow(isData))]
if (!is.null(allSignals) && length(allSignals) >= 50)
theStat <- SharpeRatio.annualized(isData[sort(allSignals),"rtn"])
if (is.null(allSignals) | length(allSignals) < 50)
theStat <- 0
return(theStat)
}
###############
tradingStatistics <- function(isOrOos = TRUE, xx = c(1,1,1,1)){
print(xx)
rtn <- ROC(data[,"close"],n=1)
rsi <- RSI(data[,"close"],n=xx[1],maType="SMA")
smas <- SMA(data[,"close"],n=xx[3])
smal <- SMA(data[,"close"],n=xx[4])
aa <- cbind(data[,"close"],rtn,rsi,smas,smal)
colnames(aa) <- c("close","rtn","rsi","smas","smal")
if (isOrOos == TRUE)
sampleData <- aa[index(aa) < "2011-01-01"]
if (isOrOos == FALSE)
sampleData <- aa[index(aa) >= "2011-01-01"]
posBuySignal <- which(sampleData[,"rsi"] <= (1 - xx[2]) & sampleData[,"smas"] > sampleData[,"smal"]) + 1
if (length(posBuySignal) == 0)
posBuySignal <- NULL
posSellSignal <- which(sampleData[,"rsi"] > xx[2] & sampleData[,"smas"] < sampleData[,"smal"]) + 1
if (length(posSellSignal) == 0)
posSellSignal <- NULL
allSignals <- c(posBuySignal,posSellSignal)
allSignals <- allSignals[which(allSignals <= nrow(sampleData))]
totalRtn <- sum(sampleData[sort(allSignals),"rtn"])
numberOfTrades <- length(sampleData[sort(allSignals),"rtn"])
hitRatio <- length(which(sampleData[sort(allSignals),"rtn"] > 0))/numberOfTrades
return(list(totalRtn=totalRtn,numberOfTrades=numberOfTrades,hitRatio=hitRatio))
}
###########
optimum <- genoud(fitnessFunction,
nvars = 4,
max = TRUE,
pop.size = 30,
max.generations = 50,
wait.generations = 15,
hard.generation.limit = TRUE,
starting.values = c(5,70,30,100),
MemoryMatrix = TRUE,
Domains = matrix(c(5,50,10,50,
50,90,50,200),
nrow=4,ncol=2),
default.domains = 4,
solution.tolerance = 0.00001,
gr = NULL,
boundary.enforcement = 2,
lexical = FALSE,
gradient.check = FALSE,
data.type.int = TRUE,
hessian = FALSE,
unif.seed = 812821,
int.seed = 53058,
print.level = 2,
share.type = 0,
instance.number = 0,
output.path = paste(outputPath,theInstrument,"_Summary.txt",sep=""),
output.append = FALSE,
project.path = paste(outputPath,theInstrument,"_Details.txt",sep=""),
P1=2, P2=8, P3=8, P4=6, P5=6, P6=6, P7=8, P8=6, P9=0,
P9mix = NULL,
BFGSburnin = 0,
BFGSfn = NULL,
BFGShelp = NULL,
cluster = FALSE,
balance = FALSE,
debug = FALSE,
control = list())
solution <- optimum$par
@jonikmen
Copy link

jonikmen commented Nov 7, 2014

HI! As i understand, posBuySignal is index of signal to buy. Why it is always empty?

@GiorgioMasiero
Copy link

Hi! I'd like to know how you can use integer value inside the genoud Domain. For instance if you have to optimize crossing of fast and slow ExponentialMAs finding their optima length. Thanks and my compliments. Giorgio

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment