|
@@ -1,10 +1,9 @@
|
|
|
package main
|
|
|
|
|
|
import (
|
|
|
- "errors"
|
|
|
"git.beejay.kim/Gshopper/sentio"
|
|
|
"git.beejay.kim/Gshopper/sentio/indicator"
|
|
|
- "math"
|
|
|
+ "git.beejay.kim/Gshopper/sentio/util"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
@@ -12,9 +11,6 @@ const (
|
|
|
ATR_MULTIPLIER = 1.5
|
|
|
ATR_PERIOD = 5
|
|
|
ATR_HHV = 4
|
|
|
-
|
|
|
- ATR_STOPLOSS_THRESHOLD = 1
|
|
|
- EXTRA_POSITION_THRESHOLD = 1.002
|
|
|
)
|
|
|
|
|
|
var Strategy = qqq{}
|
|
@@ -60,11 +56,10 @@ func (strategy qqq) PositionProbabilities() map[sentio.Side]float64 {
|
|
|
func (strategy qqq) Handle(market sentio.Market, probability sentio.Probability) error {
|
|
|
var (
|
|
|
now = market.Clock().Now()
|
|
|
- symbols = strategy.Symbols()
|
|
|
+ symbols = util.Symbols(strategy)
|
|
|
stoplosses map[string]float64
|
|
|
quotes map[string]sentio.Quote
|
|
|
orders []sentio.Order
|
|
|
- portfolio sentio.Portfolio
|
|
|
err error
|
|
|
)
|
|
|
|
|
@@ -75,19 +70,18 @@ func (strategy qqq) Handle(market sentio.Market, probability sentio.Probability)
|
|
|
|
|
|
// close all orders before market close
|
|
|
if now.Hour() == 15 && now.Minute() > 50 {
|
|
|
- return strategy.CloseAllOrders(market)
|
|
|
+ return util.CloseAllOrders(market, strategy)
|
|
|
}
|
|
|
|
|
|
// retrieve running orders
|
|
|
if orders, err = market.Orders(sentio.OrderListCriteria{
|
|
|
Status: "open",
|
|
|
Symbols: symbols,
|
|
|
- Nested: true,
|
|
|
}); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- if stoplosses, err = strategy.AtrStopLoss(market, symbols...); err != nil {
|
|
|
+ if stoplosses, err = indicator.AtrTrailingStopLoss(market, 1, ATR_PERIOD, ATR_MULTIPLIER, ATR_HHV, symbols...); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
@@ -111,7 +105,7 @@ func (strategy qqq) Handle(market sentio.Market, probability sentio.Probability)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- if f, ok := stoplosses[orders[i].GetId()]; ok && f > 0 {
|
|
|
+ if f, ok := stoplosses[orders[i].GetSymbol()]; ok && f > 0 {
|
|
|
if err = market.UpdateOrder(orders[i].GetId(), f); err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -134,10 +128,6 @@ func (strategy qqq) Handle(market sentio.Market, probability sentio.Probability)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
- if portfolio, err = market.Portfolio(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
if quotes, err = market.Quotes(symbols...); err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -147,138 +137,5 @@ func (strategy qqq) Handle(market sentio.Market, probability sentio.Probability)
|
|
|
t = sentio.LONG
|
|
|
}
|
|
|
|
|
|
- return strategy.CreateOrder(market, t, probability, portfolio, quotes, stoplosses)
|
|
|
-}
|
|
|
-
|
|
|
-func (strategy qqq) Symbols() []string {
|
|
|
- var symbols []string
|
|
|
-
|
|
|
- for side, s := range strategy.PositionSymbols() {
|
|
|
- if sentio.BASE == side {
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- symbols = append(symbols, s)
|
|
|
- }
|
|
|
-
|
|
|
- return symbols
|
|
|
-}
|
|
|
-
|
|
|
-func (strategy qqq) CloseAllOrders(market sentio.Market) error {
|
|
|
- var (
|
|
|
- symbols = strategy.Symbols()
|
|
|
- orders []sentio.Order
|
|
|
- err error
|
|
|
- )
|
|
|
-
|
|
|
- if orders, err = market.Orders(sentio.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 qqq) AtrStopLoss(market sentio.Market, symbols ...string) (map[string]float64, error) {
|
|
|
- var (
|
|
|
- stoplosses map[string]float64
|
|
|
- bars map[string][]sentio.Bar
|
|
|
- err error
|
|
|
- )
|
|
|
-
|
|
|
- if bars, err = market.HistoricalBars(symbols, time.Minute, nil); err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- stoplosses = make(map[string]float64)
|
|
|
- for s := range bars {
|
|
|
- if bars == nil || len(bars[s]) < ATR_PERIOD {
|
|
|
- return nil, errors.New("AtrStopLoss: could not calculate stoploss for too short timeseries")
|
|
|
- }
|
|
|
-
|
|
|
- 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 qqq) CreateOrder(m sentio.Market, t sentio.Side, proba sentio.Probability, p sentio.Portfolio, q map[string]sentio.Quote, sl map[string]float64) error {
|
|
|
- var (
|
|
|
- symbol = strategy.PositionSymbols()[t]
|
|
|
- position sentio.Position
|
|
|
- account sentio.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 sentio.ErrTooSmallOrder
|
|
|
- }
|
|
|
-
|
|
|
- if !has && proba.Value > threshold {
|
|
|
-
|
|
|
- // create a new order
|
|
|
- if size = uint(math.Floor(account.GetCash() * .7 / q[symbol].BidPrice)); size < 1 {
|
|
|
- return sentio.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 sentio.ErrTooSmallOrder
|
|
|
- }
|
|
|
-
|
|
|
- _, err = m.CreateOrder(symbol, size, sl[symbol])
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
+ return util.CreateOrder(market, strategy, t, probability, quotes, stoplosses)
|
|
|
}
|