Browse Source

Refactoring

Alexey Kim 1 month ago
parent
commit
72864bf995
5 changed files with 62 additions and 40 deletions
  1. 1 1
      market.go
  2. 10 0
      order_options.go
  3. 2 2
      risk_manager.go
  4. 4 3
      strategy/alpaca/ppo_250625/strategy.go
  5. 45 34
      util/order.go

+ 1 - 1
market.go

@@ -14,7 +14,7 @@ type Market interface {
 	Account() (MarketAccount, error)
 	MaxBudget() float64
 
-	CreateOrder(symbol string, limit float64, quantity uint, rm RiskManager) (Order, error)
+	CreateOrder(opts OrderOptions) error
 	UpdateOrder(orderID string, rm RiskManager) error
 	CloseOrder(order Order, recommended *float64) (float64, error)
 

+ 10 - 0
order_options.go

@@ -0,0 +1,10 @@
+package sentio
+
+type OrderOptions struct {
+	Symbol     string
+	Action     Action
+	Limit      float64
+	Size       uint
+	TakeProfit float64
+	StopLoss   float64
+}

+ 2 - 2
risk_manager.go

@@ -1,8 +1,8 @@
 package sentio
 
 type RiskManager interface {
-	StopLoss(symbol string, current float64, safe bool) float64
-	TakeProfit(symbol string, current float64, safe bool) float64
+	StopLoss(symbol string, current float64) float64
+	TakeProfit(symbol string, current float64) float64
 
 	GetBalance() (float64, float64)
 	GetPnL() (float64, float64)

+ 4 - 3
strategy/alpaca/ppo_250625/strategy.go

@@ -121,9 +121,10 @@ func (strategy qqq) Handle(turn *sentio.Turn, market sentio.Market, rs sentio.Ri
 		return err
 	}
 
-	if sentio.Action_SELL == turn.Action {
-		return nil
+	var opts sentio.OrderOptions
+	if opts, err = util.NewOrder(market, strategy, turn.Action, quotes, rs); err != nil {
+		return err
 	}
 
-	return util.CreateOrder(market, strategy, turn.Action, quotes, rs)
+	return market.CreateOrder(opts)
 }

+ 45 - 34
util/order.go

@@ -6,76 +6,87 @@ import (
 	"math"
 )
 
-func CreateOrder(
+const TradingRange = .02
+
+func NewOrder(
 	m sentio.Market,
 	s sentio.Strategy,
 	action sentio.Action,
 	quotes map[string]sentio.Quote,
 	rm sentio.RiskManager,
-) error {
+) (opts sentio.OrderOptions, err error) {
 	var (
-		symbol  string
-		account sentio.MarketAccount
-		size    uint
-		side    sentio.Side
-		bid     float64
-		tp      float64
-		sl      float64
-		ok      bool
-		err     error
+		side sentio.Side
+		bid  float64
+		ok   bool
 	)
 
 	if side = sentio.ActionToSide(action); sentio.BASE == side {
-		return errors.New("`CreateOrder`: do nothing while `sentio.BASE`")
+		err = errors.New("`CreateOrder`: do nothing while `sentio.BASE`")
+		return
 	}
 
-	if symbol, ok = s.PositionSymbols()[side]; !ok {
-		return errors.New("`CreateOrder`: unknown Side for the current strategy")
+	if opts.Symbol, ok = s.PositionSymbols()[side]; !ok {
+		err = errors.New("`CreateOrder`: unknown Side for the current strategy")
 	}
 
-	bid = sentio.ToFixed(quotes[symbol].BidPrice, 2)
-	tp = sentio.ToFixed(rm.TakeProfit(symbol, bid, false), 2)
-	sl = sentio.ToFixed(rm.StopLoss(symbol, bid, false), 2)
+	bid = sentio.ToFixed(quotes[opts.Symbol].BidPrice, 2)
+	opts.Action = sentio.Action_BUY
+	opts.TakeProfit = sentio.ToFixed(rm.TakeProfit(opts.Symbol, bid), 2)
+	opts.StopLoss = sentio.ToFixed(rm.StopLoss(opts.Symbol, bid), 2)
 
 	// Prevent orders those have too small expected profit
-	if tp < bid+0.02 {
-		return sentio.ErrLowTakeProfit
+	if opts.TakeProfit < bid+TradingRange {
+		err = sentio.ErrLowTakeProfit
+		return
 	}
 
 	// Prevent cases when order will be closed ASAP they were opened.
 	// Also, Alpaca requires at least 0.01 gap against base_price
-	if sl > bid-0.01 {
-		return sentio.ErrHighStoploss
+	if opts.StopLoss > bid-TradingRange {
+		err = sentio.ErrHighStoploss
+		return
 	}
 
-	if account, err = m.Account(); err != nil {
-		return err
+	// Invert OrderOptions if we will do SHORT for BASE symbol
+	if sentio.SHORT == side && s.PositionSymbols()[sentio.BASE] == opts.Symbol {
+		tmp := opts.StopLoss
+		opts.StopLoss = opts.TakeProfit
+		opts.TakeProfit = tmp
+
+		opts.Action = sentio.Action_SELL
 	}
 
 	var (
-		cash  = account.GetCash(false)
-		ratio float64
+		account sentio.MarketAccount
+		cash    float64
+		ratio   float64
 	)
 
+	if account, err = m.Account(); err != nil {
+		return
+	}
+
+	cash = account.GetCash(false)
 	if budget := m.MaxBudget(); budget > 0 && cash > budget {
 		cash = budget
 	}
 
-	if cash < bid {
-		return sentio.ErrTooSmallOrder
+	if cash <= bid {
+		err = sentio.ErrTooSmallOrder
+		return
 	}
 
-	if ratio = rm.GetOrderSize(symbol, bid); ratio <= 0 {
-		return sentio.ErrRiskManagementPrevent
+	if ratio = rm.GetOrderSize(opts.Symbol, bid); ratio <= 0 {
+		err = sentio.ErrRiskManagementPrevent
+		return
 	}
 
-	// create a new order
-	if size = uint(math.Floor(cash * ratio / bid)); size < 1 {
-		return sentio.ErrTooSmallOrder
+	if opts.Size = uint(math.Floor(cash * ratio / bid)); opts.Size < 1 {
+		err = sentio.ErrTooSmallOrder
 	}
 
-	_, err = m.CreateOrder(symbol, 0, size, rm)
-	return err
+	return opts, nil
 }
 
 func CloseAllOrders(m sentio.Market, s sentio.Strategy) error {