forked from stellar-deprecated/kelp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
orderConstraintsFilter.go
133 lines (118 loc) · 4.28 KB
/
orderConstraintsFilter.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
127
128
129
130
131
132
133
package plugins
import (
"fmt"
"log"
"strconv"
hProtocol "github.com/stellar/go/protocols/horizon"
"github.com/stellar/go/txnbuild"
"github.com/stellar/kelp/model"
"github.com/stellar/kelp/support/utils"
)
type orderConstraintsFilter struct {
oc *model.OrderConstraints
baseAsset hProtocol.Asset
quoteAsset hProtocol.Asset
}
var _ SubmitFilter = &orderConstraintsFilter{}
// MakeFilterOrderConstraints makes a submit filter based on the passed in orderConstraints
func MakeFilterOrderConstraints(
oc *model.OrderConstraints,
baseAsset hProtocol.Asset,
quoteAsset hProtocol.Asset,
) SubmitFilter {
return &orderConstraintsFilter{
oc: oc,
baseAsset: baseAsset,
quoteAsset: quoteAsset,
}
}
// Apply impl.
func (f *orderConstraintsFilter) Apply(
ops []txnbuild.Operation,
sellingOffers []hProtocol.Offer,
buyingOffers []hProtocol.Offer,
) ([]txnbuild.Operation, error) {
numKeep := 0
numDropped := 0
filteredOps := []txnbuild.Operation{}
for _, op := range ops {
var keep bool
var e error
var opPtr *txnbuild.ManageSellOffer
switch o := op.(type) {
case *txnbuild.ManageSellOffer:
keep, e = f.shouldKeepOffer(o)
if e != nil {
return nil, fmt.Errorf("could not transform offer (pointer case): %s", e)
}
opPtr = o
default:
keep = true
}
if keep {
filteredOps = append(filteredOps, opPtr)
numKeep++
} else {
numDropped++
// figure out how to convert the offer to a dropped state
if opPtr.OfferID == 0 {
// new offers can be dropped, so don't add to filteredOps
} else if opPtr.Amount != "0" {
// modify offers should be converted to delete offers
opCopy := *opPtr
opCopy.Amount = "0"
filteredOps = append(filteredOps, &opCopy)
} else {
return nil, fmt.Errorf("unable to drop manageOffer operation (probably a delete op that should not have reached here): offerID=%d, amountRaw=%s", opPtr.OfferID, opPtr.Amount)
}
}
}
log.Printf("orderConstraintsFilter: dropped %d, kept %d ops from original %d ops, len(filteredOps) = %d\n", numDropped, numKeep, len(ops), len(filteredOps))
return filteredOps, nil
}
func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) (bool, error) {
// delete operations should never be dropped
amountFloat, e := strconv.ParseFloat(op.Amount, 64)
if e != nil {
return false, fmt.Errorf("could not convert amount (%s) to float: %s", op.Amount, e)
}
if op.Amount == "0" || amountFloat == 0.0 {
log.Printf("orderConstraintsFilter: keeping delete operation with amount = %s\n", op.Amount)
return true, nil
}
isSell, e := utils.IsSelling(f.baseAsset, f.quoteAsset, op.Selling, op.Buying)
if e != nil {
return false, fmt.Errorf("error when running the isSelling check for offer '%+v': %s", *op, e)
}
sellPrice, e := strconv.ParseFloat(op.Price, 64)
if e != nil {
return false, fmt.Errorf("could not convert price (%s) to float: %s", op.Price, e)
}
if isSell {
baseAmount := amountFloat
quoteAmount := baseAmount * sellPrice
if baseAmount < f.oc.MinBaseVolume.AsFloat() {
log.Printf("orderConstraintsFilter: selling, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString())
return false, nil
}
if f.oc.MinQuoteVolume != nil && quoteAmount < f.oc.MinQuoteVolume.AsFloat() {
log.Printf("orderConstraintsFilter: selling, keep = (quoteAmount) %.8f < %s (MinQuoteVolume): keep = false\n", quoteAmount, f.oc.MinQuoteVolume.AsString())
return false, nil
}
log.Printf("orderConstraintsFilter: selling, baseAmount=%.8f, quoteAmount=%.8f, keep = true\n", baseAmount, quoteAmount)
return true, nil
}
// buying
quoteAmount := amountFloat
baseAmount := quoteAmount * sellPrice
if baseAmount < f.oc.MinBaseVolume.AsFloat() {
log.Printf("orderConstraintsFilter: buying, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString())
return false, nil
}
if f.oc.MinQuoteVolume != nil && quoteAmount < f.oc.MinQuoteVolume.AsFloat() {
log.Printf("orderConstraintsFilter: buying, keep = (quoteAmount) %.8f < %s (MinQuoteVolume): keep = false\n", quoteAmount, f.oc.MinQuoteVolume.AsString())
return false, nil
}
log.Printf("orderConstraintsFilter: buying, baseAmount=%.8f, quoteAmount=%.8f, keep = true\n", baseAmount, quoteAmount)
return true, nil
}