2
0

strategy.go 3.8 KB

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