Last active
June 10, 2019 19:00
-
-
Save ewancook/36fc196b733a24169dd9d12b6de9b8fd to your computer and use it in GitHub Desktop.
triangular arbitrage profitability calculator (poloniex)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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¤cyPair=%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