[Blotter-commits] r1738 - in pkg/quantstrat: R inst/tests

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Sat Mar 26 15:35:14 CET 2016


Author: bodanker
Date: 2016-03-26 15:35:13 +0100 (Sat, 26 Mar 2016)
New Revision: 1738

Modified:
   pkg/quantstrat/R/osFUNs.R
   pkg/quantstrat/inst/tests/test_osMaxPos.R
Log:
Refactor osMaxPos

Attempt to simplify function logic to make it easier to reason about.

Use as.numeric instead of as.integer to strip attributes because some
instruments allow fractional shares (e.g. mutual funds, foreign
exchange). Thanks to Brian for the correction.

Add tests for max clip size check. Refactor tests so they're easier to
change if we need to update them. It should also help avoid copy/paste
errors (e.g. the "flatten long w/orderqty = 'all'" test under "long
position, ruletype != 'risk'" incorrectly used orderside="short" instead
of orderside="long").


Modified: pkg/quantstrat/R/osFUNs.R
===================================================================
--- pkg/quantstrat/R/osFUNs.R	2016-03-26 00:42:04 UTC (rev 1737)
+++ pkg/quantstrat/R/osFUNs.R	2016-03-26 14:35:13 UTC (rev 1738)
@@ -170,34 +170,31 @@
 				orderside<-'short'
 		}
 	}
+    # TODO: need to ensure that orderside and pos align if orderside != NULL?
+    # i.e. it's possible user passes orderside = "long" when pos < 0.
 	
 	# check levels
 	# buy long
     if(orderqty>0 && orderside=='long') {
-        if ((orderqty+pos)<PosLimit[,"MaxPos"]) {
-            #we have room to expand the position
-            if(orderqty<=(PosLimit[,"MaxPos"]/PosLimit[,"LongLevels"]) ) {
-                orderqty=orderqty
-            } else {
-                orderqty = round(PosLimit[,"MaxPos"]/PosLimit[,"LongLevels"],0) #note no round lots
-            }
-        } else {
-            # this order would put us over the MaxPos limit
-            orderqty<-ifelse((PosLimit[,"MaxPos"]-pos)<=round(PosLimit[,"MaxPos"]/PosLimit[,"LongLevels"],0),PosLimit[,"MaxPos"]-pos, round(PosLimit[,"MaxPos"]/PosLimit[,"LongLevels"],0)) 
-            if(orderqty+pos>PosLimit[,"MaxPos"]) orderqty <- PosLimit[,"MaxPos"]-pos
+        # note no round lots for max clip
+        clip <- round(PosLimit[,"MaxPos"] / PosLimit[,"LongLevels"], 0)
+
+        if ((orderqty+pos) > PosLimit[,"MaxPos"]) {
+            # this order would put us beyond the MaxPos limit
+            orderqty <- PosLimit[,"MaxPos"] - pos
         }
-        return(as.integer(orderqty))
+        # check clip size
+        orderqty <- min(orderqty, clip)
+
+        return(as.numeric(orderqty))  # strip attributes
     }
     
     #sell long
     if(orderqty<0 && orderside=='long') {
-		if(ruletype=='risk'){
-          return(orderqty)
-        } 
-		if ((orderqty+pos)>=0) {
+        if(ruletype=='risk' || (orderqty+pos)>=0) {
             return(orderqty)
         } else {
-			orderqty <- -pos #flatten position, don't cross through zero
+            orderqty <- -pos #flatten position, don't cross through zero
             #TODO add code to break into two orders?
             return(orderqty)
         }
@@ -205,28 +202,23 @@
     
     #sell short
     if(orderqty<0 && orderside=='short') {
-        if ((orderqty+pos)>PosLimit[,"MinPos"]) {
-            #we have room to expand the position
-            if(orderqty>=(PosLimit[,"MinPos"]/PosLimit[,"ShortLevels"]) ) {
-                orderqty=orderqty
-            } else {
-                orderqty = round(PosLimit[,"MinPos"]/PosLimit[,"ShortLevels"],0) #note no round lots
-            }
-        } else {
-            # this order would put us over the MinPos limit
-            orderqty<-ifelse((PosLimit[,"MinPos"]-pos)>=round(PosLimit[,"MinPos"]/PosLimit[,"ShortLevels"],0),PosLimit[,"MinPos"]-pos, round(PosLimit[,"MinPos"]/PosLimit[,"ShortLevels"],0)) 
-            if(orderqty+pos>PosLimit[,"MaxPos"]) orderqty <- PosLimit[,"MinPos"]-pos
+        # note no round lots for max clip
+        clip <- round(PosLimit[,"MinPos"] / PosLimit[,"ShortLevels"], 0)
+
+        if ((orderqty+pos) < PosLimit[,"MinPos"]) {
+            # this order would put us beyond the MinPos limit
+            orderqty <- PosLimit[,"MinPos"] - pos
         }
-        return(as.integer(orderqty))
+        # check clip size
+        orderqty <- max(orderqty, clip)
+
+        return(as.numeric(orderqty))  # strip attributes
     }
     
     #buy cover short
     if(orderqty>0 && orderside=='short') {
-        if(ruletype=='risk'){
+        if(ruletype=='risk' || (orderqty+pos)<=0) {
             return(orderqty)
-        } 
-        if ((orderqty+pos)<=0) {
-            return(orderqty)
         } else {
             orderqty <- -pos #flatten position, don't cross through zero
             #TODO add code to break into two orders?

Modified: pkg/quantstrat/inst/tests/test_osMaxPos.R
===================================================================
--- pkg/quantstrat/inst/tests/test_osMaxPos.R	2016-03-26 00:42:04 UTC (rev 1737)
+++ pkg/quantstrat/inst/tests/test_osMaxPos.R	2016-03-26 14:35:13 UTC (rev 1738)
@@ -5,151 +5,180 @@
 # setup
 symbol <- "test"
 portfolio <- "test_osMaxPos"
-initPortf(portfolio, symbol, -3000)
+longPos  <-  6000
+shortPos <- -2000
+initPortf(portfolio, symbol, shortPos)
 
 addPosLimit(portfolio, symbol, "2013-09-01", 8000, 8, -4000, 4)
 timestamp <- as.Date("2013-09-09")
 
 ###############################################################################
 # short position, ruletype == "risk"
+side <- "short"
+type <- "risk"
+
 test_that("risk-flatten short w/orderqty = 'all'", {
-  qty <- osMaxPos(NULL, timestamp, "all", "", "short", portfolio, symbol, "risk")
-  expect_equal(qty, 3000)
-  qty <- osMaxPos(NULL, timestamp, "all", "", NULL, portfolio, symbol, "risk")
-  expect_equal(qty, 3000)
+  qty <- osMaxPos(NULL, timestamp, "all", "", side, portfolio, symbol, type)
+  expect_equal(qty, -shortPos)
+  qty <- osMaxPos(NULL, timestamp, "all", "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -shortPos)
 })
 
 # FIXME: Should risk be able to take position across zero?
 test_that("risk-flatten short w/orderqty > abs(position)", {
-  qty <- osMaxPos(NULL, timestamp, 4000, "", "short", portfolio, symbol, "risk")
-  expect_equal(qty, 4000)
-  qty <- osMaxPos(NULL, timestamp, 4000, "", NULL, portfolio, symbol, "risk")
-  expect_equal(qty, 4000)
+  qty <- osMaxPos(NULL, timestamp, -shortPos*2, "", side, portfolio, symbol, type)
+  expect_equal(qty, -shortPos*2)
+  qty <- osMaxPos(NULL, timestamp, -shortPos*2, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -shortPos*2)
 })
 
 test_that("risk-reduce short", {
-  qty <- osMaxPos(NULL, timestamp, 2000, "", "short", portfolio, symbol, "risk")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", side, portfolio, symbol, type)
   expect_equal(qty, 2000)
-  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, "risk")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, 2000)
 })
 
 # FIXME: What should these do? Risk rules probably shouldn't be able to increase position
 #test_that("risk-increase short within limits", {
-#  qty <- osMaxPos(NULL, timestamp, -1000, "", "short", portfolio, symbol, "risk")
-#  qty <- osMaxPos(NULL, timestamp, -1000, "", NULL, portfolio, symbol, "risk")
+#  qty <- osMaxPos(NULL, timestamp, -1000, "", side, portfolio, symbol, type)
+#  qty <- osMaxPos(NULL, timestamp, -1000, "", NULL, portfolio, symbol, type)
 #})
 #
 #test_that("risk-increase short beyond limits", {
-#  qty <- osMaxPos(NULL, timestamp, -2000, "", "short", portfolio, symbol, "risk")
-#  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, "risk")
+#  qty <- osMaxPos(NULL, timestamp, -2000, "", side, portfolio, symbol, type)
+#  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, type)
 #})
 
 ###############################################################################
 # short position, ruletype != "risk"
+type <- ""
+
 test_that("flatten short w/orderqty = 'all'", {
   # ordertype="all" is not currently supported for non-risk ruletypes
-  expect_error(osMaxPos(NULL, timestamp, "all", "", "short", portfolio, symbol, ""))
+  expect_error(osMaxPos(NULL, timestamp, "all", "", side, portfolio, symbol, type))
 })
 
 test_that("flatten short w/orderqty > abs(position)", {
-  qty <- osMaxPos(NULL, timestamp, 4000, "", "short", portfolio, symbol, "")
-  expect_equal(qty, 3000)
-  qty <- osMaxPos(NULL, timestamp, 4000, "", NULL, portfolio, symbol, "")
-  expect_equal(qty, 3000)
+  qty <- osMaxPos(NULL, timestamp, -shortPos*2, "", side, portfolio, symbol, type)
+  expect_equal(qty, -shortPos)
+  qty <- osMaxPos(NULL, timestamp, -shortPos*2, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -shortPos)
 })
 
 test_that("reduce short", {
-  qty <- osMaxPos(NULL, timestamp, 2000, "", "short", portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", side, portfolio, symbol, type)
   expect_equal(qty, 2000)
-  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, 2000)
 })
 
-test_that("increase short within limits", {
-  qty <- osMaxPos(NULL, timestamp, -1000, "", "short", portfolio, symbol, "")
+test_that("increase short within limits, < clip size", {
+  qty <- osMaxPos(NULL, timestamp, -1000, "", side, portfolio, symbol, type)
   expect_equal(qty, -1000)
-  qty <- osMaxPos(NULL, timestamp, -1000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, -1000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, -1000)
 })
 
+test_that("increase short within limits, > clip size", {
+  qty <- osMaxPos(NULL, timestamp, -1500, "", side, portfolio, symbol, type)
+  expect_equal(qty, -1000)
+  qty <- osMaxPos(NULL, timestamp, -1500, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -1000)
+})
+
 test_that("increase short beyond limits", {
-  qty <- osMaxPos(NULL, timestamp, -2000, "", "short", portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", side, portfolio, symbol, type)
   expect_equal(qty, -1000)
-  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, -1000)
 })
 
-# add transaction to make portfolio long
-suppressWarnings(addTxn(portfolio, symbol, timestamp-1L, 10000, 1, verbose=FALSE))
+# add transactions to make portfolio long
+suppressWarnings({
+  addTxn(portfolio, symbol, timestamp-2L, -shortPos, 1, verbose=FALSE)
+  addTxn(portfolio, symbol, timestamp-1L, longPos, 1, verbose=FALSE)
+})
 
 ###############################################################################
 # long position, ruletype == "risk"
+side <- "long"
+type <- "risk"
+
 test_that("risk-flatten long w/orderqty = 'all'", {
-  qty <- osMaxPos(NULL, timestamp, "all", "", "long", portfolio, symbol, "risk")
-  expect_equal(qty, -7000)
-  qty <- osMaxPos(NULL, timestamp, "all", "", NULL, portfolio, symbol, "risk")
-  expect_equal(qty, -7000)
+  qty <- osMaxPos(NULL, timestamp, "all", "", side, portfolio, symbol, type)
+  expect_equal(qty, -longPos)
+  qty <- osMaxPos(NULL, timestamp, "all", "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -longPos)
 })
 
 test_that("risk-reduce long", {
-  qty <- osMaxPos(NULL, timestamp, -2000, "", "long", portfolio, symbol, "risk")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", side, portfolio, symbol, type)
   expect_equal(qty, -2000)
-  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, "risk")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, -2000)
 })
 
 # FIXME: Should risk be able to take position across zero?
 test_that("risk-flatten long w/orderqty > abs(position)", {
-  qty <- osMaxPos(NULL, timestamp, -8000, "", "long", portfolio, symbol, "risk")
-  expect_equal(qty, -8000)
-  qty <- osMaxPos(NULL, timestamp, -8000, "", NULL, portfolio, symbol, "risk")
-  expect_equal(qty, -8000)
+  qty <- osMaxPos(NULL, timestamp, -longPos*2, "", side, portfolio, symbol, type)
+  expect_equal(qty, -longPos*2)
+  qty <- osMaxPos(NULL, timestamp, -longPos*2, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -longPos*2)
 })
 
 # FIXME: What should these do? Risk rules probably shouldn't be able to increase position
 #test_that("risk-increase long within limits", {
-#  qty <- osMaxPos(NULL, timestamp, 1000, "", "long", portfolio, symbol, "risk")
-#  qty <- osMaxPos(NULL, timestamp, 1000, "", NULL, portfolio, symbol, "risk")
+#  qty <- osMaxPos(NULL, timestamp, 1000, "", side, portfolio, symbol, type)
+#  qty <- osMaxPos(NULL, timestamp, 1000, "", NULL, portfolio, symbol, type)
 #})
 #
 #test_that("risk-increase long beyond limits", {
-#  qty <- osMaxPos(NULL, timestamp, 2000, "", "long", portfolio, symbol, "risk")
-#  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, "risk")
+#  qty <- osMaxPos(NULL, timestamp, 2000, "", side, portfolio, symbol, type)
+#  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, type)
 #})
 
 ###############################################################################
 # long position, ruletype != "risk"
+type <- ""
+
 test_that("flatten long w/orderqty = 'all'", {
   # ordertype="all" is not currently supported for non-risk ruletypes
-  expect_error(osMaxPos(NULL, timestamp, "all", "", "short", portfolio, symbol, ""))
+  expect_error(osMaxPos(NULL, timestamp, "all", "", side, portfolio, symbol, type))
 })
 
 test_that("reduce long", {
-  qty <- osMaxPos(NULL, timestamp, -2000, "", "long", portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", side, portfolio, symbol, type)
   expect_equal(qty, -2000)
-  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, -2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, -2000)
 })
 
 test_that("flatten long w/orderqty > abs(position)", {
-  qty <- osMaxPos(NULL, timestamp, -8000, "", "long", portfolio, symbol, "")
-  expect_equal(qty, -7000)
-  qty <- osMaxPos(NULL, timestamp, -8000, "", NULL, portfolio, symbol, "")
-  expect_equal(qty, -7000)
+  qty <- osMaxPos(NULL, timestamp, -longPos*2, "", side, portfolio, symbol, type)
+  expect_equal(qty, -longPos)
+  qty <- osMaxPos(NULL, timestamp, -longPos*2, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, -longPos)
 })
 
-test_that("increase long within limits", {
-  qty <- osMaxPos(NULL, timestamp, 1000, "", "long", portfolio, symbol, "")
+test_that("increase long within limits, < clip size", {
+  qty <- osMaxPos(NULL, timestamp, 1000, "", side, portfolio, symbol, type)
   expect_equal(qty, 1000)
-  qty <- osMaxPos(NULL, timestamp, 1000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, 1000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, 1000)
 })
 
+test_that("increase long within limits, > clip size", {
+  qty <- osMaxPos(NULL, timestamp, 1500, "", side, portfolio, symbol, type)
+  expect_equal(qty, 1000)
+  qty <- osMaxPos(NULL, timestamp, 1500, "", NULL, portfolio, symbol, type)
+  expect_equal(qty, 1000)
+})
+
 test_that("increase long beyond limits", {
-  qty <- osMaxPos(NULL, timestamp, 2000, "", "long", portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", side, portfolio, symbol, type)
   expect_equal(qty, 1000)
-  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, "")
+  qty <- osMaxPos(NULL, timestamp, 2000, "", NULL, portfolio, symbol, type)
   expect_equal(qty, 1000)
 })
 



More information about the Blotter-commits mailing list