order.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package util
  2. import (
  3. "errors"
  4. "git.beejay.kim/Gshopper/sentio"
  5. "math"
  6. )
  7. const TradingRange = .02
  8. func NewOrder(
  9. m sentio.Market,
  10. s sentio.Strategy,
  11. action sentio.Action,
  12. quotes map[string]sentio.Quote,
  13. rm sentio.RiskManager,
  14. ) (opts sentio.OrderOptions, err error) {
  15. var (
  16. side sentio.Side
  17. bid float64
  18. ok bool
  19. )
  20. if side = sentio.ActionToSide(action); sentio.BASE == side {
  21. err = errors.New("`CreateOrder`: do nothing while `sentio.BASE`")
  22. return
  23. }
  24. if opts.Symbol, ok = s.PositionSymbols()[side]; !ok {
  25. err = errors.New("`CreateOrder`: unknown Side for the current strategy")
  26. }
  27. bid = sentio.ToFixed(quotes[opts.Symbol].BidPrice, 2)
  28. opts.Action = sentio.Action_BUY
  29. opts.TakeProfit = sentio.ToFixed(rm.TakeProfit(opts.Symbol, bid), 2)
  30. opts.StopLoss = sentio.ToFixed(rm.StopLoss(opts.Symbol, bid), 2)
  31. // Prevent orders those have too small expected profit
  32. if opts.TakeProfit < bid*(1+TradingRange) {
  33. err = sentio.ErrLowTakeProfit
  34. return
  35. }
  36. // Prevent cases when order will be closed ASAP they were opened.
  37. // Also, Alpaca requires at least 0.01 gap against base_price
  38. if opts.StopLoss > bid*(1-TradingRange) {
  39. err = sentio.ErrHighStoploss
  40. return
  41. }
  42. // Invert OrderOptions if we will do SHORT for BASE symbol
  43. if sentio.SHORT == side && s.PositionSymbols()[sentio.BASE] == opts.Symbol {
  44. tmp := opts.StopLoss
  45. opts.StopLoss = opts.TakeProfit
  46. opts.TakeProfit = tmp
  47. opts.Action = sentio.Action_SELL
  48. }
  49. var (
  50. account sentio.MarketAccount
  51. cash float64
  52. ratio float64
  53. )
  54. if account, err = m.Account(); err != nil {
  55. return
  56. }
  57. cash = account.GetCash(false)
  58. if budget := m.MaxBudget(); budget > 0 && cash > budget {
  59. cash = budget
  60. }
  61. if cash <= bid {
  62. err = sentio.ErrTooSmallOrder
  63. return
  64. }
  65. if ratio = rm.GetOrderSize(opts.Symbol, bid); ratio <= 0 {
  66. err = sentio.ErrRiskManagementPrevent
  67. return
  68. }
  69. if opts.Size = uint(math.Floor(cash * ratio / bid)); opts.Size < 1 {
  70. err = sentio.ErrTooSmallOrder
  71. }
  72. return opts, nil
  73. }
  74. func CloseAllOrders(m sentio.Market, s sentio.Strategy) error {
  75. var (
  76. symbols = Symbols(s)
  77. orders []sentio.Order
  78. err error
  79. )
  80. if orders, err = m.Orders(sentio.OrderListCriteria{
  81. Status: "open",
  82. Symbols: symbols,
  83. }); err != nil {
  84. return err
  85. }
  86. for i := range orders {
  87. if _, err = m.CloseOrder(orders[i], nil); err != nil {
  88. return err
  89. }
  90. }
  91. return nil
  92. }