|
@@ -1,9 +1,6 @@
|
|
package sentio
|
|
package sentio
|
|
|
|
|
|
import (
|
|
import (
|
|
- "errors"
|
|
|
|
- "git.beejay.kim/Gshopper/sentio/indicator"
|
|
|
|
- "math"
|
|
|
|
"time"
|
|
"time"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -20,148 +17,139 @@ type Strategy interface {
|
|
Handle(market Market, probability Probability) error
|
|
Handle(market Market, probability Probability) error
|
|
}
|
|
}
|
|
|
|
|
|
-const (
|
|
|
|
- ATR_MULTIPLIER = 1.5
|
|
|
|
- ATR_PERIOD = 5
|
|
|
|
- ATR_HHV = 4
|
|
|
|
-
|
|
|
|
- ATR_STOPLOSS_THRESHOLD = 1
|
|
|
|
- EXTRA_POSITION_THRESHOLD = 1.002
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-type BaseStrategy struct {
|
|
|
|
- Strategy
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (strategy BaseStrategy) Symbols() []string {
|
|
|
|
- var symbols []string
|
|
|
|
-
|
|
|
|
- for side, s := range strategy.PositionSymbols() {
|
|
|
|
- if BASE == side {
|
|
|
|
- continue
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- symbols = append(symbols, s)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return symbols
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (strategy BaseStrategy) CloseAllOrders(market Market) error {
|
|
|
|
- var (
|
|
|
|
- symbols = strategy.Symbols()
|
|
|
|
- orders []Order
|
|
|
|
- err error
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
- if orders, err = market.Orders(OrderListCriteria{
|
|
|
|
- Status: "open",
|
|
|
|
- Symbols: symbols,
|
|
|
|
- Nested: true,
|
|
|
|
- }); err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for i := range orders {
|
|
|
|
- if _, err = market.CloseOrder(orders[i].GetId()); err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (strategy BaseStrategy) AtrStopLoss(market Market, symbols ...string) (map[string]float64, error) {
|
|
|
|
- var (
|
|
|
|
- stoplosses map[string]float64
|
|
|
|
- bars map[string][]Bar
|
|
|
|
- err error
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
- if bars, err = market.HistoricalBars(symbols, time.Minute, nil); err != nil {
|
|
|
|
- return nil, err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if bars == nil || len(bars) < ATR_PERIOD {
|
|
|
|
- return nil, errors.New("AtrStopLoss: could not calculate stoploss for too short timeseries")
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stoplosses = make(map[string]float64)
|
|
|
|
- for s := range bars {
|
|
|
|
- h := make([]float64, len(bars[s]))
|
|
|
|
- l := make([]float64, len(bars[s]))
|
|
|
|
- c := make([]float64, len(bars[s]))
|
|
|
|
-
|
|
|
|
- for i := range bars[s] {
|
|
|
|
- h[i] = bars[s][i].High
|
|
|
|
- l[i] = bars[s][i].Low
|
|
|
|
- c[i] = bars[s][i].Close
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- trailing := indicator.AtrTrailingStopLoss(h, l, c, ATR_PERIOD, ATR_MULTIPLIER, ATR_HHV)
|
|
|
|
- stoplosses[s] = trailing[len(trailing)-1]
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return stoplosses, nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (strategy BaseStrategy) CreateOrder(m Market, t Side, proba Probability, p Portfolio, q map[string]Quote, sl map[string]float64) error {
|
|
|
|
- var (
|
|
|
|
- symbol = strategy.PositionSymbols()[t]
|
|
|
|
- position Position
|
|
|
|
- account MarketAccount
|
|
|
|
- has = false
|
|
|
|
- threshold float64
|
|
|
|
- size uint
|
|
|
|
- ok bool
|
|
|
|
- err error
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
- // ensure portfolio
|
|
|
|
- position, has = p.Get(symbol)
|
|
|
|
-
|
|
|
|
- // define threshold
|
|
|
|
- if threshold, ok = strategy.PositionProbabilities()[t]; !ok {
|
|
|
|
- threshold = -1
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if threshold == -1 || symbol == "" {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Prevent Market.CreateOrder when BidPrice less than ATR_STOPLOSS_THRESHOLD
|
|
|
|
- if q[symbol].BidPrice/sl[symbol] < ATR_STOPLOSS_THRESHOLD {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if account, err = m.Account(); err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if account.GetCash() < q[symbol].BidPrice {
|
|
|
|
- return ErrTooSmallOrder
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if !has && proba.Value > threshold {
|
|
|
|
-
|
|
|
|
- // create a new order
|
|
|
|
- if size = uint(math.Floor(account.GetCash() * .7 / q[symbol].BidPrice)); size < 1 {
|
|
|
|
- return ErrTooSmallOrder
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _, err = m.CreateOrder(symbol, size, sl[symbol])
|
|
|
|
- return err
|
|
|
|
-
|
|
|
|
- } else if has && position.GetAvgPrice()/position.GetCurrentPrice() > EXTRA_POSITION_THRESHOLD {
|
|
|
|
-
|
|
|
|
- // create an extra position
|
|
|
|
- if size = uint(math.Floor(account.GetCash() * .5 / q[symbol].BidPrice)); size < 1 {
|
|
|
|
- return ErrTooSmallOrder
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _, err = m.CreateOrder(symbol, size, sl[symbol])
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
|
|
+//type BaseStrategy struct {
|
|
|
|
+// Strategy
|
|
|
|
+//}
|
|
|
|
+//
|
|
|
|
+//func (strategy BaseStrategy) Symbols() []string {
|
|
|
|
+// var symbols []string
|
|
|
|
+//
|
|
|
|
+// for side, s := range strategy.PositionSymbols() {
|
|
|
|
+// if BASE == side {
|
|
|
|
+// continue
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// symbols = append(symbols, s)
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// return symbols
|
|
|
|
+//}
|
|
|
|
+//
|
|
|
|
+//func (strategy BaseStrategy) CloseAllOrders(market Market) error {
|
|
|
|
+// var (
|
|
|
|
+// symbols = strategy.Symbols()
|
|
|
|
+// orders []Order
|
|
|
|
+// err error
|
|
|
|
+// )
|
|
|
|
+//
|
|
|
|
+// if orders, err = market.Orders(OrderListCriteria{
|
|
|
|
+// Status: "open",
|
|
|
|
+// Symbols: symbols,
|
|
|
|
+// Nested: true,
|
|
|
|
+// }); err != nil {
|
|
|
|
+// return err
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// for i := range orders {
|
|
|
|
+// if _, err = market.CloseOrder(orders[i].GetId()); err != nil {
|
|
|
|
+// return err
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// return nil
|
|
|
|
+//}
|
|
|
|
+//
|
|
|
|
+//func (strategy BaseStrategy) AtrStopLoss(market Market, symbols ...string) (map[string]float64, error) {
|
|
|
|
+// var (
|
|
|
|
+// stoplosses map[string]float64
|
|
|
|
+// bars map[string][]Bar
|
|
|
|
+// err error
|
|
|
|
+// )
|
|
|
|
+//
|
|
|
|
+// if bars, err = market.HistoricalBars(symbols, time.Minute, nil); err != nil {
|
|
|
|
+// return nil, err
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if bars == nil || len(bars) < ATR_PERIOD {
|
|
|
|
+// return nil, errors.New("AtrStopLoss: could not calculate stoploss for too short timeseries")
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// stoplosses = make(map[string]float64)
|
|
|
|
+// for s := range bars {
|
|
|
|
+// h := make([]float64, len(bars[s]))
|
|
|
|
+// l := make([]float64, len(bars[s]))
|
|
|
|
+// c := make([]float64, len(bars[s]))
|
|
|
|
+//
|
|
|
|
+// for i := range bars[s] {
|
|
|
|
+// h[i] = bars[s][i].High
|
|
|
|
+// l[i] = bars[s][i].Low
|
|
|
|
+// c[i] = bars[s][i].Close
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// trailing := indicator.AtrTrailingStopLoss(h, l, c, ATR_PERIOD, ATR_MULTIPLIER, ATR_HHV)
|
|
|
|
+// stoplosses[s] = trailing[len(trailing)-1]
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// return stoplosses, nil
|
|
|
|
+//}
|
|
|
|
+//
|
|
|
|
+//func (strategy BaseStrategy) CreateOrder(m Market, t Side, proba Probability, p Portfolio, q map[string]Quote, sl map[string]float64) error {
|
|
|
|
+// var (
|
|
|
|
+// symbol = strategy.PositionSymbols()[t]
|
|
|
|
+// position Position
|
|
|
|
+// account MarketAccount
|
|
|
|
+// has = false
|
|
|
|
+// threshold float64
|
|
|
|
+// size uint
|
|
|
|
+// ok bool
|
|
|
|
+// err error
|
|
|
|
+// )
|
|
|
|
+//
|
|
|
|
+// // ensure portfolio
|
|
|
|
+// position, has = p.Get(symbol)
|
|
|
|
+//
|
|
|
|
+// // define threshold
|
|
|
|
+// if threshold, ok = strategy.PositionProbabilities()[t]; !ok {
|
|
|
|
+// threshold = -1
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if threshold == -1 || symbol == "" {
|
|
|
|
+// return nil
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// // Prevent Market.CreateOrder when BidPrice less than ATR_STOPLOSS_THRESHOLD
|
|
|
|
+// if q[symbol].BidPrice/sl[symbol] < ATR_STOPLOSS_THRESHOLD {
|
|
|
|
+// return nil
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if account, err = m.Account(); err != nil {
|
|
|
|
+// return err
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if account.GetCash() < q[symbol].BidPrice {
|
|
|
|
+// return ErrTooSmallOrder
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if !has && proba.Value > threshold {
|
|
|
|
+//
|
|
|
|
+// // create a new order
|
|
|
|
+// if size = uint(math.Floor(account.GetCash() * .7 / q[symbol].BidPrice)); size < 1 {
|
|
|
|
+// return ErrTooSmallOrder
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// _, err = m.CreateOrder(symbol, size, sl[symbol])
|
|
|
|
+// return err
|
|
|
|
+//
|
|
|
|
+// } else if has && position.GetAvgPrice()/position.GetCurrentPrice() > EXTRA_POSITION_THRESHOLD {
|
|
|
|
+//
|
|
|
|
+// // create an extra position
|
|
|
|
+// if size = uint(math.Floor(account.GetCash() * .5 / q[symbol].BidPrice)); size < 1 {
|
|
|
|
+// return ErrTooSmallOrder
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// _, err = m.CreateOrder(symbol, size, sl[symbol])
|
|
|
|
+// return err
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// return nil
|
|
|
|
+//}
|