2

I have been scratching my head for the last few days trying to understand how to limit the number of position in a strategy. Its a channel breakout strategy (go long/shirt the 20d breakout channel with a 10d high/low stop loss.

I don't want the system to pyramid. Only 1 position is accepted i.e - if on day 1 I have a signal, and the market keeps trending, it will print new signals but they have to be dismissed as we are already in a position.

I tried everything i've found but i have been unable to achieve anything. I know I have to tweak with osMaxPos and addPosLimit but it seems i'm doing it wrong.

Here is my code. Thanks in advance.

#Import des données
GBPUSD <- getdata("GBPUSD.csv")
GBPUSD <- getdata("GBPUSD.csv")
AUDUSD <- getdata("AUDUSD.csv")
EURUSD <- getdata("EURUSD.csv")
XAUUSD <- getdata("XAUUSD.csv")
EURCHF <- getdata("EURCHF.csv")

### Création des devises
currency(c("USD","EUR","AUD","GBP","XAU","CHF"))
exchange_rate(c("EURUSD","GBPUSD","AUDUSD","XAUUSD","EURCHF"),"USD")
symbols <- c("GBPUSD","AUDUSD","EURUSD")
tradesize <- 1000000



init.date <- "2001-09-04"    #date d'initialisation de l'environement
start.date <- "2001-10-01"       #1ere date du jeu de donnée
end.date <- Sys.Date()       #dernière date du jeu de donnée
initial.capital <- 1000000      #Capital de départ
Breakout <- strategy("Breakout")


portfolio.st <- account.st <- strat.st <- "Breakout"

if (!exists('.blotter')) .blotter <- new.env()
if (!exists('.strategy')) .strategy <- new.env()

initPortf(portfolio.st,        #nom du book
          symbols = symbols,  #list des instruments
          initDate=init.date,  #date de départ du book
          currency='USD')     #devise de référence du book

initAcct(account.st,                 #nom du compte
         portfolios = portfolio.st,  #nom du portfeuille rattaché au compte
         initDate = init.date,       #date de départ du compte
         currency = "USD",           #devise du compte
         initEq = initial.capital)   #capital de départ du compte

initOrders(portfolio.st,            #initialisation du container des orgers
           initDate = init.date)    #date de départ du book d'ordre

strategy("Breakout",store = TRUE)


#Definition des indicateurs
add.indicator("Breakout",
              name = "DonchianChannel",
              arguments=list(HL=quote(cbind(Hi(mktdata)[,1],Lo(mktdata)[,1])), n=20,include.lag=TRUE), label="Donchian20")

add.indicator("Breakout",
              name = "DonchianChannel",
              arguments=list(HL=quote(cbind(Hi(mktdata)[,1],Lo(mktdata)[,1])), n=10,include.lag=TRUE), label="Donchian10")


##Definition des signaux

add.signal("Breakout",                #nom de la strategie
           name="sigCrossover",      #type de signal
           arguments = list(columns =c("Close","high.Donchian20"), #liste des colonnes pour déterminer le signal
                            relationship="gt"),   #type de relation du signal (sup ou égal, sup, inférieur etc..)
           label = "long")        #label de la colonne du signal

add.signal("Breakout",                #nom de la strategie
           name="sigCrossover",      #type de signal
           arguments = list(columns =c("Close","low.Donchian10"), #liste des colonnes pour déterminer le signal
                            relationship="lt"),   #type de relation du signal (sup ou égal, sup, inférieur etc..)
           label = "exitlong")        #label de la colonne du signal


add.signal("Breakout",                #nom de la strategie
           name="sigCrossover",      #type de signal
           arguments = list(columns =c("Close","low.Donchian20"), #liste des colonnes pour déterminer le signal
                            relationship="lt"),   #type de relation du signal (sup ou égal, sup, inférieur etc..)
           label = "short")   

add.signal("Breakout",                #nom de la strategie
           name="sigCrossover",      #type de signal
           arguments = list(columns =c("Close","high.Donchian10"), #liste des colonnes pour déterminer le signal
                            relationship="gt"),   #type de relation du signal (sup ou égal, sup, inférieur etc..)
           label = "exitshort")        #label de la colonne du signal


#Limite

#addPosLimit( portfolio = "Breakout", # add position limit rules
#             symbol = "AUDUSD",
#            timestamp = init.date,
#            maxpos = tradesize)

addPosLimit("Breakout","AUDUSD",maxpos = 1, minpos = -1,timestamp =  as.POSIXct(init.date))
getPosLimit(portfolio = "Breakout","AUDUSD", timestamp = as.POSIXct(init.date))

##Definition des règles

add.rule("Breakout",                               #nom de la strategie 
         name = "ruleSignal",                      #
         arguments = list(sigcol ="long",          #nom de la colonne à vérifier
                          sigval = TRUE,           #Application de la règle si signal
                          orderqty=tradesize,        #taille de l'ordre
                          osFun = osMaxPos,
                          replace = FALSE,
                          ordertype = "market",    #type d'ordre
                          orderside ="long"),   #sens
         type = "enter",          #ouverture ou fermeture de pose
         label = "Enterlong")    #label si exécution

add.rule("Breakout",                                  #nom de la strategie 
         name = "ruleSignal",                      #
         arguments = list(sigcol ="exitlong",          #nom de la colonne à vérifier
                          sigval = TRUE,           #Application de la règle si signal
                          orderqty="all",        #taille de l'ordre
                          replace = FALSE,
                          ordertype = "market",    #type d'ordre
                          orderside ="long"),   #sens
         type = "exit",          #ouverture ou fermeture de pose
         label = "Exitlong")    #label si exécution


add.rule("Breakout",                                  #nom de la strategie 
         name = "ruleSignal",                      #
         arguments = list(sigcol ="short",          #nom de la colonne à vérifier
                          sigval = TRUE,           #Application de la règle si signal
                          orderqty=-tradesize,#taille de l'ordre
                          replace = FALSE,
                          ordertype = "market",    #type d'ordre
                          orderside ="short"),   #sens
         type = "enter",          #ouverture ou fermeture de pose
         label = "Entershort")    #label si exécution

add.rule("Breakout",                                  #nom de la strategie 
         name = "ruleSignal",                      #
         arguments = list(sigcol ="exitshort",          #nom de la colonne à vérifier
                          sigval = TRUE,           #Application de la règle si signal
                          orderqty="all",#taille de l'ordre
                          osFun = osMaxPos,
                          replace = FALSE,
                          ordertype = "market",    #type d'ordre
                          orderside ="short"),   #sens
         type = "exit",          #ouverture ou fermeture de pose
         label = "Exitshort")    #label si exécution






out <- applyStrategy("Breakout", portfolios = portfolio.st)
NicolasB
  • 83
  • 5
  • You need to specify what package contains the `getdata` function. You also need to provide some data (we cannot access the CSV files on your computer). – Joshua Ulrich Jan 20 '17 at 12:38

1 Answers1

4

There are quite a few problems with your code. I'll try to explain all of them.

Initialization

You usually do not need to set initDate in your calls to initPortf, initAcct, and initOrders. Setting that value incorrectly can cause issues. So those calls should be:

initPortf(portfolio.st,       #nom du book
          symbols = symbols,  #list des instruments
          currency='USD')     #devise de référence du book

initAcct(account.st,                 #nom du compte
         portfolios = portfolio.st,  #nom du portfeuille rattaché au compte
         currency = "USD",           #devise du compte
         initEq = initial.capital)   #capital de départ du compte

initOrders(portfolio.st)             #initialisation du container des orgers

Position limits

You set max/min trade size to 1 in your call to addPosLimit, but your trade size is 1 million. So any order will be rejected because it would put you over your position limit. You should also know that the timestamp argument to addPosLimit determines when the limits go into effect. If you always want them in effect, you should set the timestamp to a time before the first observation in your data. Also note that you only created position limits for AUDUSD. You need to create position limits for each symbol.

addPosLimit("Breakout", "GBPUSD", maxpos = tradesize, timestamp = start(GBPUSD)-1)
addPosLimit("Breakout", "AUDUSD", maxpos = tradesize, timestamp = start(AUDUSD)-1)
addPosLimit("Breakout", "EURUSD", maxpos = tradesize, timestamp = start(EURUSD)-1)

Rules

One problem is that you passed osFun to ruleSignal. ruleSignal does not have an osFun argument. The argument is osFUN (case matters). The other problem is that you specified osFun = osMaxPos on your short exit rule, not the entry rule.

add.rule("Breakout", name = "ruleSignal",
         arguments = list(sigcol = "long",      #nom de la colonne à vérifier
                          sigval = TRUE,        #Application de la règle si signal
                          orderqty = tradesize, #taille de l'ordre
                          osFUN = osMaxPos,
                          replace = FALSE,
                          ordertype = "market", #type d'ordre
                          orderside = "long"),  #sens
         type = "enter", label = "Enterlong")

add.rule("Breakout", name = "ruleSignal",
         arguments = list(sigcol = "exitlong",  #nom de la colonne à vérifier
                          sigval = TRUE,        #Application de la règle si signal
                          orderqty = "all",     #taille de l'ordre
                          replace = FALSE,
                          ordertype = "market", #type d'ordre
                          orderside = "long"),  #sens
         type = "exit", label = "Exitlong")

add.rule("Breakout", name = "ruleSignal",
         arguments = list(sigcol = "short",     #nom de la colonne à vérifier
                          sigval = TRUE,        #Application de la règle si signal
                          orderqty = -tradesize,#taille de l'ordre
                          osFUN = osMaxPos,
                          replace = FALSE,
                          ordertype = "market",  #type d'ordre
                          orderside = "short"),  #sens
         type = "enter", label = "Entershort")

add.rule("Breakout", name = "ruleSignal",
         arguments = list(sigcol = "exitshort",  #nom de la colonne à vérifier
                          sigval = TRUE,         #Application de la règle si signal
                          orderqty = "all",      #taille de l'ordre
                          replace = FALSE,
                          ordertype = "market",  #type d'ordre
                          orderside = "short"),  #sens
         type = "exit", label = "Exitshort")
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • 1
    You are fantastic. Thanks for taking the time to analyse my bad code. – NicolasB Jan 20 '17 at 14:22
  • @NicolasB You should consider accepting this very thorough answer – FXQuantTrader Feb 06 '17 at 16:46
  • what do you mean @FXQuantTrader ? – NicolasB Feb 08 '17 at 14:05
  • @NicolasB: see [What should I do when someone answers my question?](http://stackoverflow.com/help/someone-answers). – Joshua Ulrich Feb 08 '17 at 15:19
  • I accepted the answer. Once again, I greatly appreciate your help Joshua :) – NicolasB Feb 09 '17 at 16:13
  • I've been trying this with a futures strategy where my max position is 1/-1. This means that if I trade a reversal, I would expect an order size of 2 (to go from position -1 to position 1 or vice versa). Yet in my order book, no order exceeds size 1. Can you help me figure out what I'm doing wrong? – TheDarkSaint Nov 01 '18 at 20:01