package util import ( "errors" "git.beejay.kim/Gshopper/sentio" "math" ) const TradingRange = .02 func NewOrder( m sentio.Market, s sentio.Strategy, action sentio.Action, quotes map[string]sentio.Quote, rm sentio.RiskManager, ) (opts sentio.OrderOptions, err error) { var ( side sentio.Side bid float64 ok bool ) if side = sentio.ActionToSide(action); sentio.BASE == side { err = errors.New("`CreateOrder`: do nothing while `sentio.BASE`") return } if opts.Symbol, ok = s.PositionSymbols()[side]; !ok { err = errors.New("`CreateOrder`: unknown Side for the current strategy") } 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 opts.TakeProfit < bid*(1+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 opts.StopLoss > bid*(1-TradingRange) { err = sentio.ErrHighStoploss return } // 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 ( 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 { err = sentio.ErrTooSmallOrder return } if ratio = rm.GetOrderSize(opts.Symbol, bid); ratio <= 0 { err = sentio.ErrRiskManagementPrevent return } if opts.Size = uint(math.Floor(cash * ratio / bid)); opts.Size < 1 { err = sentio.ErrTooSmallOrder } return opts, nil } func CloseAllOrders(m sentio.Market, s sentio.Strategy) error { var ( symbols = Symbols(s) orders []sentio.Order err error ) if orders, err = m.Orders(sentio.OrderListCriteria{ Status: "open", Symbols: symbols, }); err != nil { return err } for i := range orders { if _, err = m.CloseOrder(orders[i], nil); err != nil { return err } } return nil }