forked from stellar-deprecated/kelp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomposeStrategy.go
126 lines (109 loc) · 3.9 KB
/
composeStrategy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package plugins
import (
"fmt"
"github.com/stellar/kelp/api"
"github.com/stellar/kelp/model"
"github.com/stellar/go/build"
hProtocol "github.com/stellar/go/protocols/horizon"
"github.com/stellar/go/support/errors"
"github.com/stellar/kelp/support/utils"
)
// composeStrategy is a strategy that is composed of two sub-strategies
type composeStrategy struct {
assetBase *hProtocol.Asset
assetQuote *hProtocol.Asset
buyStrat api.SideStrategy
sellStrat api.SideStrategy
}
// ensure it implements Strategy
var _ api.Strategy = &composeStrategy{}
// makeComposeStrategy is a factory method for composeStrategy
func makeComposeStrategy(
assetBase *hProtocol.Asset,
assetQuote *hProtocol.Asset,
buyStrat api.SideStrategy,
sellStrat api.SideStrategy,
) api.Strategy {
return &composeStrategy{
assetBase: assetBase,
assetQuote: assetQuote,
buyStrat: buyStrat,
sellStrat: sellStrat,
}
}
// PruneExistingOffers impl
func (s *composeStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) {
pruneOps1, newBuyingAOffers := s.buyStrat.PruneExistingOffers(buyingAOffers)
pruneOps2, newSellingAOffers := s.sellStrat.PruneExistingOffers(sellingAOffers)
pruneOps1 = append(pruneOps1, pruneOps2...)
return pruneOps1, newBuyingAOffers, newSellingAOffers
}
// PreUpdate impl
func (s *composeStrategy) PreUpdate(maxAssetBase float64, maxAssetQuote float64, trustBase float64, trustQuote float64) error {
// swap assets (base/quote) for buying strategy
e1 := s.buyStrat.PreUpdate(maxAssetQuote, maxAssetBase, trustQuote, trustBase)
// assets maintain same ordering for selling
e2 := s.sellStrat.PreUpdate(maxAssetBase, maxAssetQuote, trustBase, trustQuote)
if e1 == nil && e2 == nil {
return nil
}
if e1 != nil && e2 != nil {
return fmt.Errorf("errors on both sides: buying (= %s) and selling (= %s)", e1, e2)
}
if e1 != nil {
return errors.Wrap(e1, "error in buying sub-strategy")
}
return errors.Wrap(e2, "error in selling sub-strategy")
}
// UpdateWithOps impl
func (s *composeStrategy) UpdateWithOps(
buyingAOffers []hProtocol.Offer,
sellingAOffers []hProtocol.Offer,
) ([]build.TransactionMutator, error) {
// buy side, flip newTopBuyPrice because it will be inverted from this parent strategy's context of base/quote
buyOps, newTopBuyPriceInverted, e1 := s.buyStrat.UpdateWithOps(buyingAOffers)
newTopBuyPrice := model.InvertNumber(newTopBuyPriceInverted)
// sell side
sellOps, _, e2 := s.sellStrat.UpdateWithOps(sellingAOffers)
// check for errors
ops := []build.TransactionMutator{}
if e1 != nil && e2 != nil {
return ops, fmt.Errorf("errors on both sides: buying (= %s) and selling (= %s)", e1, e2)
} else if e1 != nil {
return ops, errors.Wrap(e1, "error in buying sub-strategy")
} else if e2 != nil {
return ops, errors.Wrap(e2, "error in selling sub-strategy")
}
// combine ops correctly based on possible crossing offers
if newTopBuyPrice != nil && len(sellingAOffers) > 0 && newTopBuyPrice.AsFloat() >= utils.PriceAsFloat(sellingAOffers[0].Price) {
ops = append(ops, sellOps...)
ops = append(ops, buyOps...)
} else {
ops = append(ops, buyOps...)
ops = append(ops, sellOps...)
}
return ops, nil
}
// PostUpdate impl
func (s *composeStrategy) PostUpdate() error {
return nil
}
// GetFillHandlers impl
func (s *composeStrategy) GetFillHandlers() ([]api.FillHandler, error) {
buyFillHandlers, e := s.buyStrat.GetFillHandlers()
if e != nil {
return nil, fmt.Errorf("error while getting fill handlers for buy side")
}
sellFillHandlers, e := s.sellStrat.GetFillHandlers()
if e != nil {
return nil, fmt.Errorf("error while getting fill handlers for sell side")
}
handlers := []api.FillHandler{}
if buyFillHandlers != nil {
handlers = append(handlers, buyFillHandlers...)
}
if sellFillHandlers != nil {
handlers = append(handlers, sellFillHandlers...)
}
return handlers, nil
}