|
@@ -6,76 +6,87 @@ import (
|
|
|
"math"
|
|
|
)
|
|
|
|
|
|
-func CreateOrder(
|
|
|
+const TradingRange = .02
|
|
|
+
|
|
|
+func NewOrder(
|
|
|
m sentio.Market,
|
|
|
s sentio.Strategy,
|
|
|
action sentio.Action,
|
|
|
quotes map[string]sentio.Quote,
|
|
|
rm sentio.RiskManager,
|
|
|
-) error {
|
|
|
+) (opts sentio.OrderOptions, err error) {
|
|
|
var (
|
|
|
- symbol string
|
|
|
- account sentio.MarketAccount
|
|
|
- size uint
|
|
|
- side sentio.Side
|
|
|
- bid float64
|
|
|
- tp float64
|
|
|
- sl float64
|
|
|
- ok bool
|
|
|
- err error
|
|
|
+ side sentio.Side
|
|
|
+ bid float64
|
|
|
+ ok bool
|
|
|
)
|
|
|
|
|
|
if side = sentio.ActionToSide(action); sentio.BASE == side {
|
|
|
- return errors.New("`CreateOrder`: do nothing while `sentio.BASE`")
|
|
|
+ err = errors.New("`CreateOrder`: do nothing while `sentio.BASE`")
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- if symbol, ok = s.PositionSymbols()[side]; !ok {
|
|
|
- return errors.New("`CreateOrder`: unknown Side for the current strategy")
|
|
|
+ if opts.Symbol, ok = s.PositionSymbols()[side]; !ok {
|
|
|
+ err = errors.New("`CreateOrder`: unknown Side for the current strategy")
|
|
|
}
|
|
|
|
|
|
- bid = sentio.ToFixed(quotes[symbol].BidPrice, 2)
|
|
|
- tp = sentio.ToFixed(rm.TakeProfit(symbol, bid, false), 2)
|
|
|
- sl = sentio.ToFixed(rm.StopLoss(symbol, bid, false), 2)
|
|
|
+ bid = sentio.ToFixed(quotes[opts.Symbol].BidPrice, 2)
|
|
|
+ opts.Action = sentio.Action_BUY
|
|
|
+ opts.TakeProfit = sentio.ToFixed(rm.TakeProfit(opts.Symbol, bid), 2)
|
|
|
+ opts.StopLoss = sentio.ToFixed(rm.StopLoss(opts.Symbol, bid), 2)
|
|
|
|
|
|
// Prevent orders those have too small expected profit
|
|
|
- if tp < bid+0.02 {
|
|
|
- return sentio.ErrLowTakeProfit
|
|
|
+ if opts.TakeProfit < bid+TradingRange {
|
|
|
+ err = sentio.ErrLowTakeProfit
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
// Prevent cases when order will be closed ASAP they were opened.
|
|
|
// Also, Alpaca requires at least 0.01 gap against base_price
|
|
|
- if sl > bid-0.01 {
|
|
|
- return sentio.ErrHighStoploss
|
|
|
+ if opts.StopLoss > bid-TradingRange {
|
|
|
+ err = sentio.ErrHighStoploss
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- if account, err = m.Account(); err != nil {
|
|
|
- return err
|
|
|
+ // Invert OrderOptions if we will do SHORT for BASE symbol
|
|
|
+ if sentio.SHORT == side && s.PositionSymbols()[sentio.BASE] == opts.Symbol {
|
|
|
+ tmp := opts.StopLoss
|
|
|
+ opts.StopLoss = opts.TakeProfit
|
|
|
+ opts.TakeProfit = tmp
|
|
|
+
|
|
|
+ opts.Action = sentio.Action_SELL
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
- cash = account.GetCash(false)
|
|
|
- ratio float64
|
|
|
+ account sentio.MarketAccount
|
|
|
+ cash float64
|
|
|
+ ratio float64
|
|
|
)
|
|
|
|
|
|
+ if account, err = m.Account(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ cash = account.GetCash(false)
|
|
|
if budget := m.MaxBudget(); budget > 0 && cash > budget {
|
|
|
cash = budget
|
|
|
}
|
|
|
|
|
|
- if cash < bid {
|
|
|
- return sentio.ErrTooSmallOrder
|
|
|
+ if cash <= bid {
|
|
|
+ err = sentio.ErrTooSmallOrder
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- if ratio = rm.GetOrderSize(symbol, bid); ratio <= 0 {
|
|
|
- return sentio.ErrRiskManagementPrevent
|
|
|
+ if ratio = rm.GetOrderSize(opts.Symbol, bid); ratio <= 0 {
|
|
|
+ err = sentio.ErrRiskManagementPrevent
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- // create a new order
|
|
|
- if size = uint(math.Floor(cash * ratio / bid)); size < 1 {
|
|
|
- return sentio.ErrTooSmallOrder
|
|
|
+ if opts.Size = uint(math.Floor(cash * ratio / bid)); opts.Size < 1 {
|
|
|
+ err = sentio.ErrTooSmallOrder
|
|
|
}
|
|
|
|
|
|
- _, err = m.CreateOrder(symbol, 0, size, rm)
|
|
|
- return err
|
|
|
+ return opts, nil
|
|
|
}
|
|
|
|
|
|
func CloseAllOrders(m sentio.Market, s sentio.Strategy) error {
|