2
0

strategy.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package main
  2. import (
  3. "fmt"
  4. "git.beejay.kim/Gshopper/sentio"
  5. "git.beejay.kim/Gshopper/sentio/indicator"
  6. "time"
  7. )
  8. const (
  9. ATR_MULTIPLIER = 1.5
  10. ATR_PERIOD = 14
  11. ATR_HHV = 10
  12. )
  13. var Strategy = alpacaQQQ{}
  14. type alpacaQQQ struct{}
  15. func (s alpacaQQQ) Name() string {
  16. return "Alpaca: QQQ [TQQQ : SQQQ]"
  17. }
  18. func (s alpacaQQQ) Model() string {
  19. return "qqq15"
  20. }
  21. func (s alpacaQQQ) MarketId() string {
  22. return "alpaca"
  23. }
  24. func (s alpacaQQQ) PositionSymbols() map[sentio.Side]string {
  25. return map[sentio.Side]string{
  26. sentio.BASE: "QQQ",
  27. sentio.LONG: "TQQQ",
  28. sentio.SHORT: "SQQQ",
  29. }
  30. }
  31. func (s alpacaQQQ) Interval() uint8 {
  32. return 5
  33. }
  34. func (s alpacaQQQ) Cooldown(periods uint8) time.Duration {
  35. return time.Minute * time.Duration(s.Interval()*periods)
  36. }
  37. func (s alpacaQQQ) Handle(market sentio.Market, ts time.Time, proba float64) ([]sentio.StrategyOrder, error) {
  38. var (
  39. portfolio sentio.Portfolio
  40. orders []sentio.StrategyOrder
  41. now = market.Time().Now()
  42. err error
  43. )
  44. // skip too early trades
  45. if now.Hour() == 9 && now.Minute() < 45 {
  46. return orders, nil
  47. }
  48. if portfolio, err = market.Portfolio(); err != nil {
  49. return nil, err
  50. }
  51. for side, symbol := range s.PositionSymbols() {
  52. var (
  53. position sentio.Position
  54. ok bool
  55. )
  56. // no need to trade BASE quote
  57. if sentio.BASE == side {
  58. continue
  59. }
  60. if portfolio != nil {
  61. position, ok = portfolio.Get(symbol)
  62. ok = ok && position != nil && position.GetSize() != 0
  63. } else {
  64. ok = false
  65. }
  66. if ok {
  67. var (
  68. sl []float64
  69. bars []sentio.Bar
  70. )
  71. if bars, err = market.HistoricalBars(symbol, time.Minute, nil); err == nil && len(bars) > 0 {
  72. h := make([]float64, len(bars))
  73. l := make([]float64, len(bars))
  74. c := make([]float64, len(bars))
  75. for i := range bars {
  76. h[i] = bars[i].High
  77. l[i] = bars[i].Low
  78. c[i] = bars[i].Close
  79. }
  80. sl = indicator.AtrTrailingStopLoss(h, l, c, ATR_PERIOD, ATR_MULTIPLIER, ATR_HHV)
  81. fmt.Printf("ATR Trailing StopLoss: [%f]\n", sl[len(sl)-1])
  82. if position.GetCurrentPrice() < sl[len(sl)-1] {
  83. return []sentio.StrategyOrder{{
  84. Symbol: symbol,
  85. Action: sentio.OrderSell,
  86. Ratio: 1,
  87. }}, nil
  88. }
  89. }
  90. }
  91. // Close positions before market closed
  92. if ok && now.Hour() == 15 && now.Minute() > 55 {
  93. return []sentio.StrategyOrder{{
  94. Symbol: symbol,
  95. Action: sentio.OrderSell,
  96. Ratio: 1,
  97. }}, nil
  98. }
  99. if proba < 0 {
  100. continue
  101. }
  102. // Close LONG position
  103. if ok && sentio.LONG == side && proba < 1.0008 {
  104. return []sentio.StrategyOrder{{
  105. Symbol: symbol,
  106. Action: sentio.OrderSell,
  107. Ratio: 1,
  108. }}, nil
  109. }
  110. // Close SHORT position
  111. if ok && sentio.SHORT == side && proba > .9998 {
  112. return []sentio.StrategyOrder{{
  113. Symbol: symbol,
  114. Action: sentio.OrderSell,
  115. Ratio: 1,
  116. }}, nil
  117. }
  118. // Prevent BUYs for delayed probas
  119. if ts.Add(time.Minute * time.Duration(int64(s.Interval()/2))).Before(now) {
  120. continue
  121. }
  122. // Prevent BUYs on closing market
  123. if now.Hour() == 15 && now.Minute() > 46 {
  124. continue
  125. }
  126. if sentio.LONG == side && proba > 1 {
  127. size := float64(0)
  128. if ok && position.GetAvgPrice()/position.GetCurrentPrice() > 1.002 {
  129. // extra position with cheaper price
  130. size = .4
  131. } else if !ok && proba > 1.0008 {
  132. // new trade position
  133. size = .6
  134. }
  135. if size > 0 {
  136. orders = append(orders, sentio.StrategyOrder{
  137. Symbol: symbol,
  138. Action: sentio.OrderBuy,
  139. Ratio: size,
  140. })
  141. }
  142. continue
  143. }
  144. if sentio.SHORT == side && proba < 1 {
  145. size := float64(0)
  146. if ok && position.GetAvgPrice()/position.GetCurrentPrice() > 1.002 {
  147. // extra position with cheaper price
  148. size = .4
  149. } else if !ok && proba < .9990 {
  150. // new trade position
  151. size = .6
  152. }
  153. if size > 0 {
  154. orders = append(orders, sentio.StrategyOrder{
  155. Symbol: symbol,
  156. Action: sentio.OrderBuy,
  157. Ratio: size,
  158. })
  159. }
  160. continue
  161. }
  162. }
  163. return orders, nil
  164. }