Skip to content

Instantly share code, notes, and snippets.

@ewancook
Last active June 10, 2019 19:00
Show Gist options
  • Save ewancook/36fc196b733a24169dd9d12b6de9b8fd to your computer and use it in GitHub Desktop.
Save ewancook/36fc196b733a24169dd9d12b6de9b8fd to your computer and use it in GitHub Desktop.
triangular arbitrage profitability calculator (poloniex)
package main
import (
"encoding/json"
"flag"
"fmt"
"math"
"net/http"
"strconv"
"time"
)
const (
// orderBookURL is the Poloniex API endpoint used to return a single order book for a given currency
orderBookURL = "https://poloniex.com/public?command=returnOrderBook&currencyPair=%s&depth=1"
)
// orderBook represents the order book.
type orderBook struct {
Asks [][]interface{} `json:"asks"`
Bids [][]interface{} `json:"bids"`
}
// order represents an individual order in the Order Book.
type order struct {
price, amount float64
}
// data represents the data used in calculating the triangular arbitrage value.
type data struct {
asks, bids order
}
func priceFromBookType(i [][]interface{}) (float64, error) {
return strconv.ParseFloat(i[0][0].(string), 64)
}
func getData(pair string) (d *data, err error) {
book := orderBook{}
response, err := http.Get(fmt.Sprintf(orderBookURL, pair))
if err != nil {
return nil, err
}
defer response.Body.Close()
if err := json.NewDecoder(response.Body).Decode(&book); err != nil {
return nil, err
}
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
asks := order{amount: book.Asks[0][1].(float64)}
bids := order{amount: book.Bids[0][1].(float64)}
if asks.price, err = priceFromBookType(book.Asks); err != nil {
return nil, err
}
if bids.price, err = priceFromBookType(book.Bids); err != nil {
return nil, err
}
return &data{asks, bids}, nil
}
func calculate(pairs [3]string, fee float64, quit chan<- error) {
books := make([]*data, 3)
for i, pair := range pairs {
book, err := getData(pair)
if err != nil {
quit <- err
return
}
books[i] = book
}
forward := books[0].bids.price / books[1].asks.price * books[2].bids.price * fee
reverse := books[1].bids.price / books[2].asks.price / books[0].asks.price * fee
fmt.Printf("[%s]\tforward: %f\treverse: %f\n", time.Now().Format("15:04:05"), forward, reverse)
}
func main() {
tickPeriod := flag.Duration("t", (3 * time.Second), "the ticking period")
fee := flag.Float64("fee", 0.0025, "the fee for an individual transaction")
flag.Parse()
// quit is used to terminate the program on an error
quit := make(chan error)
// timer is a ticker used to repeatedly call calculate()
timer := time.NewTicker(*tickPeriod)
// totalFee is the cube of 1- fee (set by Poloniex; 3 transactions in total)
totalFee := math.Pow(1-*fee, 3)
// pairs are the currency pairs used for this example
pairs := [3]string{"BTC_LTC", "USDT_LTC", "USDT_BTC"}
go func() {
for _ = range timer.C {
calculate(pairs, totalFee, quit)
}
}()
fmt.Println(<-quit)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment