2
0

strategy.go 3.1 KB

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