|
@@ -0,0 +1,135 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "git.beejay.kim/Gshopper/sentio"
|
|
|
+ "git.beejay.kim/Gshopper/sentio/util"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+var Strategy = qqq{}
|
|
|
+
|
|
|
+type qqq struct{}
|
|
|
+
|
|
|
+func (strategy qqq) Name() string {
|
|
|
+ return "Alpaca: QQQ [TQQQ : SQQQ]"
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) Model() string {
|
|
|
+ return "stocks_dqn_seed0_250325_094456"
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) MarketId() string {
|
|
|
+ return "alpaca"
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) Interval() uint8 {
|
|
|
+ return 3
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) PositionSymbols() map[sentio.Side]string {
|
|
|
+ return map[sentio.Side]string{
|
|
|
+ sentio.BASE: "QQQ",
|
|
|
+ sentio.LONG: "TQQQ",
|
|
|
+ sentio.SHORT: "SQQQ",
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) MaxTradeDuration() time.Duration {
|
|
|
+ return time.Duration(strategy.Interval()) * time.Minute * 3
|
|
|
+}
|
|
|
+
|
|
|
+func (strategy qqq) Handle(turn *sentio.Turn, market sentio.Market, rs sentio.RiskManager) error {
|
|
|
+ if market == nil || turn == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ now = market.Clock().Now()
|
|
|
+ symbols = util.Symbols(strategy)
|
|
|
+ quotes map[string]sentio.Quote
|
|
|
+ orders []sentio.Order
|
|
|
+ err error
|
|
|
+ )
|
|
|
+
|
|
|
+ // skip too early orders
|
|
|
+ if now.Hour() == 9 && now.Minute() < 44 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // close all orders before market close
|
|
|
+ if now.Hour() == 15 && now.Minute() > 52 {
|
|
|
+ return util.CloseAllOrders(market, strategy)
|
|
|
+ }
|
|
|
+
|
|
|
+ // retrieve running orders
|
|
|
+ if orders, err = market.Orders(sentio.OrderListCriteria{
|
|
|
+ Status: "open",
|
|
|
+ Symbols: symbols,
|
|
|
+ }); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ // update stoplosses or close running orders
|
|
|
+ var (
|
|
|
+ ts = turn.Time.AsTime().Round(time.Minute)
|
|
|
+ hasClosedOrders = false
|
|
|
+ )
|
|
|
+
|
|
|
+ for i := range orders {
|
|
|
+ if util.IsLongOrder(orders[i], strategy) &&
|
|
|
+ sentio.IsAction(turn.Action, sentio.Action_HOLD, sentio.Action_SELL, sentio.Action_DOUBLE_SELL) &&
|
|
|
+ ts.Before(time.Now()) {
|
|
|
+ if _, err = market.CloseOrder(orders[i]); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ hasClosedOrders = true
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if util.IsShortOrder(orders[i], strategy) &&
|
|
|
+ sentio.IsAction(turn.Action, sentio.Action_HOLD, sentio.Action_BUY, sentio.Action_DOUBLE_BUY) &&
|
|
|
+ ts.Before(time.Now()) {
|
|
|
+ if _, err = market.CloseOrder(orders[i]); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ hasClosedOrders = true
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if orders[i].GetCreatedAt().Round(time.Minute).Add(strategy.MaxTradeDuration()).Before(time.Now()) {
|
|
|
+ if _, err = market.CloseOrder(orders[i]); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ hasClosedOrders = true
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if err = market.UpdateOrder(orders[i].GetId(), rs); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Prevent new orders if we just closed one
|
|
|
+ if hasClosedOrders || len(orders) > 0 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Prevent BUYs on closing market
|
|
|
+ if now.Hour() == 15 && now.Minute() > 45 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Prevent Market.CreateOrder while probability is not clear
|
|
|
+ if sentio.Action_HOLD == turn.Action || ts.After(time.Now()) {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if quotes, err = market.Quotes(); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return util.CreateOrder(market, strategy, turn.Action, quotes, rs)
|
|
|
+}
|