我有一个简单的信号策略
0 = 平掉所有仓位
1 = 开仓买入(如果有的话平仓卖出)
-1= 开仓(如果有则关闭买入)
交易时只能开设一个仓位
这是生成假数据和计算信号的代码
require(quantstrat)
set.seed(1)
fake_data <- rnorm(100) |> cumsum() |> xts(order.by=as.POSIXct(x=60*1:100, origin='2021-07-01'))
colnames(fake_data) <-'Close'
make_seq <- function() sample(c(-1,0,1),size=1) |> rep(sample(3:20,1))
fake_data$signal <- lapply(1:50,\(x) make_seq()) |> unlist() |> tail(n = length(fake_data))
# signal
chart_Series(fake_data)
abline(h=0)
fake_data$buy_open <- 0
fake_data$buy_close <- 0
fake_data$sell_open <- 0
fake_data$sell_close <- 0
S <- fake_data$signal |> coredata() |> as.vector()
for(i in 2:nrow(fake_data)){
if(S[i-1]!= 1 & S[i]== 1) fake_data$buy_open[i] <- 1
if(S[i-1]== 1 & S[i]!= 1) fake_data$buy_close[i] <- 1
if(S[i-1]!= -1 & S[i]== -1) fake_data$sell_open[i] <- 1
if(S[i-1]== -1 & S[i]!= -1) fake_data$sell_close[i] <- 1
}
接下来我创建交易规则
rm.strat(strat.st)
strat.st <- "FAKESTRAT"
currency("USD")
stock("fake_data",currency = "USD")
initPortf(strat.st, symbols="fake_data")
initEq<-1000
initAcct(strat.st, portfolios=strat.st, initEq=initEq)
initOrders(portfolio=strat.st)
strategy(name=strat.st,store=TRUE)
addPosLimit("FAKESTRAT", "fake_data", maxpos = 1, timestamp = start(fake_data)-1)
# enterLong exitLong
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="buy_open",
sigval=TRUE,
orderqty=1,
ordertype='market',
orderside='long',
osFUN = osMaxPos),
type="enter",
label="enterLong"
)
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="buy_close",
sigval=TRUE,
orderqty="all",
ordertype='market',
orderside='long'),
type="exit",
label="exitLong"
)
# enterShort exitShort
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="sell_open",
sigval=TRUE,
orderqty=-1,
ordertype='market',
orderside='short',
osFUN = osMaxPos),
type="enter",
label="enterShort"
)
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="sell_close",
sigval=TRUE,
orderqty="all",
ordertype='market',
orderside='short'),
type="exit",
label="exitShort"
)
out<-applyStrategy(strat.st , portfolios=strat.st, verbose=T)
updatePortf(strat.st)
book <- getOrderBook(portfolio=strat.st)
....
print(book)
book
$FAKESTRAT
$FAKESTRAT$fake_data
Order.Qty Order.Price Order.Type Order.Side Order.Threshold
2021-07-01 03:24:00 -1 3.59680448297358 market short <NA>
2021-07-01 03:40:00 all 3.68104715087989 market short <NA>
2021-07-01 03:40:00 1 3.68104715087989 market long <NA>
2021-07-01 03:54:00 -1 4.02025008047271 market short <NA>
2021-07-01 04:12:00 all 10.7346453103169 market short <NA>
2021-07-01 04:35:00 -1 13.8781211399328 market short <NA>
Order.Status Order.StatusTime Prefer Order.Set Txn.Fees Rule
2021-07-01 03:24:00 closed 2021-07-01 03:25:00 <NA> 0 enterShort
2021-07-01 03:40:00 replaced 2021-07-01 03:40:00 <NA> 0 exitShort
2021-07-01 03:40:00 closed 2021-07-01 03:41:00 <NA> 0 enterLong
2021-07-01 03:54:00 closed 2021-07-01 03:55:00 <NA> 0 enterShort
2021-07-01 04:12:00 closed 2021-07-01 04:13:00 <NA> 0 exitShort
2021-07-01 04:35:00 closed 2021-07-01 04:36:00 <NA> 0 enterShort
Time.In.Force
2021-07-01 03:24:00
2021-07-01 03:40:00
2021-07-01 03:40:00
2021-07-01 03:54:00
2021-07-01 04:12:00
2021-07-01 04:35:00
我不明白为什么持仓是多头
2021-07-01 03:40:00 1 3.68104715087989 market long
卖出信号到来时尚未平仓
2021-07-01 03:54:00 -1 4.02025008047271 market short
您的每个入仓 (
enterLong
, enterShort
) 和平仓 (exitLong
, exitShort
) 仓位的功能仅专注于其指定操作:根据相应信号进场或退出多头或空头头寸列(buy_open
、buy_close
、sell_open
、sell_close
)。这些规则中没有机制可以在即将开仓时检查是否存在相反的仓位。
例如,当触发
enterShort
规则时,它不会首先检查是否已经存在需要平仓的多头头寸。它只是继续进入空头头寸。 enterLong
规则也是如此;在开立多头头寸之前,它不会检查现有的空头头寸。
因此,如果进入空头头寸的信号出现,您当前的设置似乎没有任何逻辑可以平仓多头头寸,反之亦然。
如果我们以您订单簿的这一部分为例:
2021-07-01 03:40:00 1 3.68104715087989 market long
2021-07-01 03:54:00 -1 4.02025008047271 market short
您在
2021-07-01 03:40:00
建多仓,卖出信号在 2021-07-01 03:54:00
到达。然而,当卖出信号到来时,现有多头头寸并未平仓。
osMaxPos
函数来调整订单大小,以确保您一次只有一个持仓,但它不包含“关闭”现有相反仓位的逻辑。 osMaxPos
只查看当前持仓类型(多头或空头)并限制,但不平仓相反类型。当收到进入空头头寸的信号时,您可能需要实现额外的逻辑来平仓多头头寸,反之亦然。这可能是一个自定义订单大小功能(),用于在执行交易之前检查当前头寸。如果现有仓位与新信号相反,该函数将需要平仓。例如,您可以定义一个
osCloseOpposite
函数:
osCloseOpposite <- function(timestamp, orderqty, portfolio, symbol, ...) {
# Close opposite position if it exists
currentPos <- getPosQty(portfolio, symbol, timestamp)
if (orderqty > 0 && currentPos < 0) {
# Close existing short position
return(-currentPos)
} else if (orderqty < 0 && currentPos > 0) {
# Close existing long position
return(-currentPos)
}
# If no opposite position, apply osMaxPos logic
return(osMaxPos(timestamp, orderqty, portfolio, symbol, ...))
}
然后将此函数用作现有规则中的
osFUN
:
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="sell_open",
sigval=TRUE,
orderqty=-1,
ordertype='market',
orderside='short',
osFUN = osCloseOpposite),
type="enter",
label="enterShort"
)
对
enterLong
规则执行相同操作。这样,您的自定义函数将检查现有仓位,如果与新信号相反则将其平仓。
replace
变量中 您需要做的就是将其包含在开仓和平仓规则中
replace=TRUE
平仓
replace=FALSE
持仓
# enterLong exitLong
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="buy_open",
sigval=TRUE,
replace=FALSE,
orderqty=1,
ordertype='market',
orderside='long',
osFUN = osMaxPos),
type="enter",
label="enterLong"
)
add.rule(strat.st,"ruleSignal",
arguments=list(sigcol="buy_close",
sigval=TRUE,
replace=TRUE,
orderqty="all",
ordertype='market',
orderside='long'),
type="exit",
label="exitLong"
)
销售规则也需要做同样的事情