Skip to content
This repository was archived by the owner on Feb 1, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion accounting/pnl/pnl.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,5 @@ func loadAccount(client *horizon.Client, address string) horizon.Account {

func makeCmcFeed(cmcRef string) (api.PriceFeed, error) {
url := fmt.Sprintf("https://api.coinmarketcap.com/v1/ticker/%s/", cmcRef)
return plugins.MakePriceFeed("crypto", url)
return plugins.MakePriceFeed("crypto", url, false)
}
6 changes: 6 additions & 0 deletions examples/configs/trader/sample_buysell.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ DATA_TYPE_A="exchange"
# use "kraken" or any of the ccxt-exchanges (run `kelp exchanges` for full list)
# examples: "kraken", "ccxt-kraken", "ccxt-binance", "ccxt-poloniex", "ccxt-bittrex"
DATA_FEED_A_URL="kraken/XXLM/ZUSD"
# whether to invert the price received from the feed; this allows more complex price derivations
DATA_FEED_A_INVERT=false
# uncomment to use binance, poloniex, or bittrex as your price feed. You will need to set up CCXT to use this, see the "Using CCXT" section in the README for details.
# be careful about using USD vs. USDT since some exchanges support only one, or both, or in some cases neither.
#DATA_FEED_A_URL="ccxt-kraken/XLM/USD"
Expand All @@ -27,10 +29,12 @@ DATA_FEED_A_URL="kraken/XXLM/ZUSD"
#DATA_TYPE_A="crypto"
# this is the URL to a coinmarketcap feed which the bot understands.
#DATA_FEED_A_URL="https://api.coinmarketcap.com/v1/ticker/stellar/"
#DATA_FEED_A_INVERT=false

# this is a fixed value of 1 here because the exchange and sdex priceFeeds provides a ratio of two assets.
DATA_TYPE_B="fixed"
DATA_FEED_B_URL="1.0"
DATA_FEED_B_INVERT=false

# sample priceFeed with the "fiat" type.
#DATA_TYPE_B="fiat"
Expand All @@ -43,6 +47,8 @@ DATA_FEED_B_URL="1.0"
# this is a string representing a SDEX pair; the format is CODE:ISSUER/CODE:ISSUER
# for XLM leave the issuer string blank
# DATA_FEED_A_URL="COUPON:GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI/XLM:"
# sdex feeds don't need to be inverted because the sdex can read the orderbook either direction, so you can just swap the assets above
# DATA_FEED_A_INVERT=false

# what value of a price change triggers re-creating an offer. Price change refers to the existing price of the offer vs. what price we want to set. value is a percentage specified as a decimal number (0 < value < 1.00)
PRICE_TOLERANCE=0.001
Expand Down
7 changes: 7 additions & 0 deletions examples/configs/trader/sample_sell.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ DATA_TYPE_A="exchange"
# use "kraken" or any of the ccxt-exchanges (run `kelp exchanges` for full list)
# examples: "kraken", "ccxt-kraken", "ccxt-binance", "ccxt-poloniex", "ccxt-bittrex"
DATA_FEED_A_URL="kraken/XXLM/ZUSD"
# whether to invert the price received from the feed; this allows more complex price derivations
DATA_FEED_A_INVERT=false
# uncomment to use binance, poloniex, or bittrex as your price feed. You will need to set up CCXT to use this, see the "Using CCXT" section in the README for details.
# be careful about using USD vs. USDT since some exchanges support only one, or both, or in some cases neither.
#DATA_FEED_A_URL="ccxt-kraken/XLM/USD"
Expand All @@ -29,22 +31,27 @@ DATA_FEED_A_URL="kraken/XXLM/ZUSD"
#DATA_TYPE_A="crypto"
# this is the URL to a coinmarketcap feed which the bot understands.
#DATA_FEED_A_URL="https://api.coinmarketcap.com/v1/ticker/stellar/"
#DATA_FEED_A_INVERT=false

# this is a fixed value of 1 here because the exchange and sdex priceFeeds provides a ratio of two assets.
DATA_TYPE_B="fixed"
DATA_FEED_B_URL="1.0"
DATA_FEED_B_INVERT=false

# sample priceFeed with the "fiat" type.
#DATA_TYPE_B="fiat"
# you can use a service like apilayer.net to get prices for fiat if you want real-time updates. You will need to fill in the access_key in this url
#DATA_FEED_B_URL="http://apilayer.net/api/live?access_key=&currencies=NGN"
#DATA_FEED_B_INVERT=false

# sample priceFeed with the "sdex" type
# this feed pulls from the SDEX, you can use the asset you're trading or something else, like the same coin from another issuer
# DATA_TYPE_A = "sdex"
# this is a string representing a SDEX pair; the format is CODE:ISSUER/CODE:ISSUER
# for XLM leave the issuer string blank
# DATA_FEED_A_URL="COUPON:GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI/XLM:"
# sdex feeds don't need to be inverted because the sdex can read the orderbook either direction, so you can just swap the assets above
# DATA_FEED_A_INVERT=false

# what value of a price change triggers re-creating an offer. Price change refers to the existing price of the offer vs. what price we want to set. value is a percentage specified as a decimal number (0 < value < 1.00)
PRICE_TOLERANCE=0.001
Expand Down
6 changes: 6 additions & 0 deletions plugins/buysellStrategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ type buySellConfig struct {
AmountOfABase float64 `valid:"-" toml:"AMOUNT_OF_A_BASE"` // the size of order to keep on either side
DataTypeA string `valid:"-" toml:"DATA_TYPE_A"`
DataFeedAURL string `valid:"-" toml:"DATA_FEED_A_URL"`
DataFeedAInvert bool `valid:"-" toml:"DATA_FEED_A_INVERT"`
DataTypeB string `valid:"-" toml:"DATA_TYPE_B"`
DataFeedBURL string `valid:"-" toml:"DATA_FEED_B_URL"`
DataFeedBInvert bool `valid:"-" toml:"DATA_FEED_B_INVERT"`
Levels []staticLevel `valid:"-" toml:"LEVELS"`
}

Expand All @@ -46,8 +48,10 @@ func makeBuySellStrategy(
sellSideFeedPair, e := MakeFeedPair(
config.DataTypeA,
config.DataFeedAURL,
config.DataFeedAInvert,
config.DataTypeB,
config.DataFeedBURL,
config.DataFeedBInvert,
)
if e != nil {
return nil, fmt.Errorf("cannot make the buysell strategy because we could not make the sell side feed pair: %s", e)
Expand Down Expand Up @@ -80,8 +84,10 @@ func makeBuySellStrategy(
buySideFeedPair, e := MakeFeedPair(
config.DataTypeB,
config.DataFeedBURL,
config.DataFeedBInvert,
config.DataTypeA,
config.DataFeedAURL,
config.DataFeedAInvert,
)
if e != nil {
return nil, fmt.Errorf("cannot make the buysell strategy because we could not make the buy side feed pair: %s", e)
Expand Down
8 changes: 7 additions & 1 deletion plugins/cmcFeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,18 @@ type cmcAPIReturn struct {
type cmcFeed struct {
url string
client http.Client
invert bool
}

// ensure that it implements PriceFeed
var _ api.PriceFeed = &cmcFeed{}

// newCMCFeed creates a new CMC Feed from a URL
func newCMCFeed(url string) *cmcFeed {
func newCMCFeed(url string, invert bool) *cmcFeed {
m := new(cmcFeed)
m.url = url
m.client = http.Client{Timeout: 10 * time.Second}
m.invert = invert
return m
}

Expand All @@ -66,5 +68,9 @@ func (c *cmcFeed) GetPrice() (float64, error) {
return 0, err
}

if c.invert {
pA = 1.0 / pA
}

return pA, nil
}
9 changes: 8 additions & 1 deletion plugins/exchangeFeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ type exchangeFeed struct {
name string
tickerAPI *api.TickerAPI
pairs []model.TradingPair
invert bool
}

// ensure that it implements PriceFeed
var _ api.PriceFeed = &exchangeFeed{}

func newExchangeFeed(name string, tickerAPI *api.TickerAPI, pair *model.TradingPair) *exchangeFeed {
func newExchangeFeed(name string, tickerAPI *api.TickerAPI, pair *model.TradingPair, invert bool) *exchangeFeed {
return &exchangeFeed{
name: name,
tickerAPI: tickerAPI,
pairs: []model.TradingPair{*pair},
invert: invert,
}
}

Expand All @@ -40,6 +42,11 @@ func (f *exchangeFeed) GetPrice() (float64, error) {
}

centerPrice := (p.BidPrice.AsFloat() + p.AskPrice.AsFloat()) / 2

if f.invert {
centerPrice = 1.0 / centerPrice
}

log.Printf("price from exchange feed (%s): bidPrice=%.7f, askPrice=%.7f, centerPrice=%.7f", f.name, p.BidPrice.AsFloat(), p.AskPrice.AsFloat(), centerPrice)
return centerPrice, nil
}
9 changes: 7 additions & 2 deletions plugins/fiatFeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ type fiatAPIReturn struct {
type fiatFeed struct {
url string
client http.Client
invert bool
}

// ensure that it implements PriceFeed
var _ api.PriceFeed = &fiatFeed{}

func newFiatFeed(url string) *fiatFeed {
func newFiatFeed(url string, invert bool) *fiatFeed {
m := new(fiatFeed)
m.url = url
m.client = http.Client{Timeout: 10 * time.Second}
Expand All @@ -51,5 +52,9 @@ func (f *fiatFeed) GetPrice() (float64, error) {
pA = value
}

return (1.0 / pA), nil
if !f.invert {
pA = 1.0 / pA
}

return (pA), nil
}
14 changes: 7 additions & 7 deletions plugins/priceFeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ func SetPrivateSdexHack(api *horizon.Client, ieif *IEIF, network build.Network)
}

// MakePriceFeed makes a PriceFeed
func MakePriceFeed(feedType string, url string) (api.PriceFeed, error) {
func MakePriceFeed(feedType string, url string, invert bool) (api.PriceFeed, error) {
switch feedType {
case "crypto":
return newCMCFeed(url), nil
return newCMCFeed(url, invert), nil
case "fiat":
return newFiatFeed(url), nil
return newFiatFeed(url, invert), nil
case "fixed":
return newFixedFeed(url), nil
case "exchange":
Expand All @@ -63,7 +63,7 @@ func MakePriceFeed(feedType string, url string) (api.PriceFeed, error) {
Quote: quoteAsset,
}
tickerAPI := api.TickerAPI(exchange)
return newExchangeFeed(url, &tickerAPI, &tradingPair), nil
return newExchangeFeed(url, &tickerAPI, &tradingPair, invert), nil
case "sdex":
sdex, e := makeSDEXFeed(url)
if e != nil {
Expand All @@ -75,13 +75,13 @@ func MakePriceFeed(feedType string, url string) (api.PriceFeed, error) {
}

// MakeFeedPair is the factory method that we expose
func MakeFeedPair(dataTypeA, dataFeedAUrl, dataTypeB, dataFeedBUrl string) (*api.FeedPair, error) {
feedA, e := MakePriceFeed(dataTypeA, dataFeedAUrl)
func MakeFeedPair(dataTypeA string, dataFeedAUrl string, dataTypeAInvert bool, dataTypeB string, dataFeedBUrl string, dataFeedBInvert bool) (*api.FeedPair, error) {
feedA, e := MakePriceFeed(dataTypeA, dataFeedAUrl, dataTypeAInvert)
if e != nil {
return nil, fmt.Errorf("cannot make a feed pair because of an error when making priceFeed A: %s", e)
}

feedB, e := MakePriceFeed(dataTypeB, dataFeedBUrl)
feedB, e := MakePriceFeed(dataTypeB, dataFeedBUrl, dataFeedBInvert)
if e != nil {
return nil, fmt.Errorf("cannot make a feed pair because of an error when making priceFeed B: %s", e)
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/sellStrategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import (
type sellConfig struct {
DataTypeA string `valid:"-" toml:"DATA_TYPE_A"`
DataFeedAURL string `valid:"-" toml:"DATA_FEED_A_URL"`
DataFeedAInvert bool `valid:"-" toml:"DATA_FEED_A_INVERT"`
DataTypeB string `valid:"-" toml:"DATA_TYPE_B"`
DataFeedBURL string `valid:"-" toml:"DATA_FEED_B_URL"`
DataFeedBInvert bool `valid:"-" toml:"DATA_FEED_B_INVERT"`
PriceTolerance float64 `valid:"-" toml:"PRICE_TOLERANCE"`
AmountTolerance float64 `valid:"-" toml:"AMOUNT_TOLERANCE"`
AmountOfABase float64 `valid:"-" toml:"AMOUNT_OF_A_BASE"` // the size of order
Expand All @@ -42,8 +44,10 @@ func makeSellStrategy(
pf, e := MakeFeedPair(
config.DataTypeA,
config.DataFeedAURL,
config.DataFeedAInvert,
config.DataTypeB,
config.DataFeedBURL,
config.DataFeedBInvert,
)
if e != nil {
return nil, fmt.Errorf("cannot make the sell strategy because we could not make the feed pair: %s", e)
Expand Down