From cf8efa499d79091cd061ce487c990e27e4c0fb54 Mon Sep 17 00:00:00 2001 From: japko-7 Date: Mon, 20 Apr 2020 16:52:14 +0200 Subject: [PATCH 1/6] l3: general market observer class with basic functions for getting bid, ask and spread + bitbay_observer specialized in https://bitbay.net/en/public-api; functions in main class for refreshing and printing status --- barracuda/src/main/Main.java | 56 +++++++++++++++ .../src/market_observer/bitbay_observer.java | 68 +++++++++++++++++++ .../src/market_observer/market_observer.java | 30 ++++++++ 3 files changed, 154 insertions(+) create mode 100644 barracuda/src/main/Main.java create mode 100644 barracuda/src/market_observer/bitbay_observer.java create mode 100644 barracuda/src/market_observer/market_observer.java diff --git a/barracuda/src/main/Main.java b/barracuda/src/main/Main.java new file mode 100644 index 00000000..8f999492 --- /dev/null +++ b/barracuda/src/main/Main.java @@ -0,0 +1,56 @@ +package main; + +import market_observer.*; + +import java.time.*; +import java.util.ArrayList; + +public class Main +{ + private static ArrayList market_observers = new ArrayList(); + private static int refresh_interval; + + private static void refresh() + { + System.out.println("\n----- Status for " + Instant.now() + " -----"); + for ( market_observer observer: market_observers ) + { + observer.update_data(); + observer.print_status(); + } + } + + private static void refresh_periodically() + { + while (true) + { + refresh(); + try + { + Thread.sleep(refresh_interval); + } + catch(InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + } + } + + public static void main(String[] args) + { + refresh_interval = 4950; + + market_observers.add(new bitbay_observer("BTC")); + market_observers.add(new bitbay_observer("LTC")); + market_observers.add(new bitbay_observer("LSK")); + market_observers.add(new bitbay_observer("GAME")); + market_observers.add(new bitbay_observer("REP")); + market_observers.add(new bitbay_observer("PAY")); + + Thread thread = new Thread(Main::refresh_periodically); + thread.setDaemon(true); + thread.start(); + try { thread.join(); } + catch (InterruptedException e) { Thread.currentThread().interrupt(); } + } +} diff --git a/barracuda/src/market_observer/bitbay_observer.java b/barracuda/src/market_observer/bitbay_observer.java new file mode 100644 index 00000000..f0196fa2 --- /dev/null +++ b/barracuda/src/market_observer/bitbay_observer.java @@ -0,0 +1,68 @@ +package market_observer; + +import java.io.*; +import java.net.*; + +public class bitbay_observer extends market_observer +{ + private URL currency_url; + + public bitbay_observer(String currency) + { + super(currency, "bitbay"); + try + { + currency_url = new URL("https://bitbay.net/API/Public/"+ currency + "/ticker.json"); + update_data(); + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency); + e.printStackTrace(); + } + } + + @Override + public void update_data() + { + try + { + URLConnection conn = currency_url.openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) get_data_from_json_string(line); + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (IOException e) { e.printStackTrace(); } + } + + private void get_data_from_json_string(String json_string) + { +// System.out.println(json_string); + if(json_string == null) return; + + try + { + float bid = Float.parseFloat( json_string.substring( json_string.indexOf("\"bid\":") + 6, + json_string.indexOf(',', json_string.indexOf( "\"bid\":" ) ) ) ); + float ask = Float.parseFloat( json_string.substring( json_string.indexOf("\"ask\":") + 6, + json_string.indexOf(',', json_string.indexOf( "\"ask\":") ) ) ); + + bid_price = bid; + ask_price = ask; + +// System.out.println("bid: "+ bid + ", ask: " + ask); + } + catch (java.lang.NumberFormatException ignored){} + + } +} diff --git a/barracuda/src/market_observer/market_observer.java b/barracuda/src/market_observer/market_observer.java new file mode 100644 index 00000000..880951dc --- /dev/null +++ b/barracuda/src/market_observer/market_observer.java @@ -0,0 +1,30 @@ +package market_observer; + +public abstract class market_observer +{ + float bid_price = 0, ask_price = 0; + private String currency, name; + + market_observer(String currency, String name) + { + this.currency = currency; + this.name = name; + } + public float bid_price(){ return bid_price; } + public float ask_price(){ return ask_price; } + public float spread(){ return (ask_price - bid_price) / bid_price;} + + public void print_status() + { + System.out.println + ( + currency + " @ " + + name + ": bid = " + + bid_price + ", ask = " + + ask_price + ", spread = " + + String.format("%.02f", 100 * spread()) + "%" + ); + } + + public abstract void update_data(); +} From 792318951083dffd91c347ca2c2fc282546a527f Mon Sep 17 00:00:00 2001 From: japko-7 Date: Mon, 4 May 2020 14:50:50 +0200 Subject: [PATCH 2/6] added amounts and commission rates --- .../src/market_observer/bitbay_observer.java | 27 ++++++++++++------- .../src/market_observer/market_observer.java | 13 ++++++--- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/barracuda/src/market_observer/bitbay_observer.java b/barracuda/src/market_observer/bitbay_observer.java index f0196fa2..79d97937 100644 --- a/barracuda/src/market_observer/bitbay_observer.java +++ b/barracuda/src/market_observer/bitbay_observer.java @@ -9,10 +9,10 @@ public class bitbay_observer extends market_observer public bitbay_observer(String currency) { - super(currency, "bitbay"); + super(currency, "bitbay", 0.005f); try { - currency_url = new URL("https://bitbay.net/API/Public/"+ currency + "/ticker.json"); + currency_url = new URL("https://bitbay.net/API/Public/"+ currency + "/orderbook.json"); update_data(); } catch (MalformedURLException e) @@ -48,21 +48,28 @@ public void update_data() private void get_data_from_json_string(String json_string) { // System.out.println(json_string); +// return; if(json_string == null) return; try { - float bid = Float.parseFloat( json_string.substring( json_string.indexOf("\"bid\":") + 6, - json_string.indexOf(',', json_string.indexOf( "\"bid\":" ) ) ) ); - float ask = Float.parseFloat( json_string.substring( json_string.indexOf("\"ask\":") + 6, - json_string.indexOf(',', json_string.indexOf( "\"ask\":") ) ) ); + int bid_price_start_position = json_string.indexOf("\"bids\":[[") + 9; + int bid_price_end_position = json_string.indexOf(',', bid_price_start_position ); + int bid_amount_end_position = json_string.indexOf(']', bid_price_end_position ); - bid_price = bid; - ask_price = ask; + int ask_price_start_position = json_string.indexOf("\"asks\":[[") + 9; + int ask_price_end_position = json_string.indexOf(',', ask_price_start_position ); + int ask_amount_end_position = json_string.indexOf(']', ask_price_end_position ); -// System.out.println("bid: "+ bid + ", ask: " + ask); + bid_price = Float.parseFloat( json_string.substring(bid_price_start_position, bid_price_end_position ) ); + bid_amount = Float.parseFloat( json_string.substring(bid_price_end_position + 1, bid_amount_end_position ) ); + + ask_price = Float.parseFloat( json_string.substring(ask_price_start_position, ask_price_end_position ) ); + ask_amount = Float.parseFloat( json_string.substring(ask_price_end_position + 1, ask_amount_end_position ) ); + +// System.out.println("bid: " + bid_amount + " ✖️ " + bid_price + "; ask: " + ask_amount + " ✖️ " + ask_price); } - catch (java.lang.NumberFormatException ignored){} + catch (java.lang.NumberFormatException ignored){ /* System.out.println(ignored); */ } } } diff --git a/barracuda/src/market_observer/market_observer.java b/barracuda/src/market_observer/market_observer.java index 880951dc..e13ae5c7 100644 --- a/barracuda/src/market_observer/market_observer.java +++ b/barracuda/src/market_observer/market_observer.java @@ -2,16 +2,21 @@ public abstract class market_observer { - float bid_price = 0, ask_price = 0; + float bid_price = 0, ask_price = 0, bid_amount = 0, ask_amount = 0; + private float commission_rate = 0.005f; private String currency, name; - market_observer(String currency, String name) + market_observer(String currency, String name, float commission_rate) { this.currency = currency; this.name = name; + this.commission_rate = commission_rate; } + public float bid_price(){ return bid_price; } public float ask_price(){ return ask_price; } + public float bid_amount(){ return bid_amount; } + public float ask_amount(){ return ask_amount; } public float spread(){ return (ask_price - bid_price) / bid_price;} public void print_status() @@ -20,8 +25,8 @@ public void print_status() ( currency + " @ " + name + ": bid = " + - bid_price + ", ask = " + - ask_price + ", spread = " + + bid_amount + " ✖️ " + bid_price + ", ask = " + + ask_amount + " ✖️ " + ask_price + ", spread = " + String.format("%.02f", 100 * spread()) + "%" ); } From 9306a9c2a5b05afed115257e3ce568f254f94e8d Mon Sep 17 00:00:00 2001 From: japko-7 Date: Sat, 9 May 2020 19:11:23 +0200 Subject: [PATCH 3/6] added more and markets --- barracuda/src/main/Main.java | 16 ++-- .../src/market_observer/bitbay_observer.java | 3 +- .../market_observer/bitfinex_observer.java | 79 ++++++++++++++++++ .../src/market_observer/bybit_observer.java | 83 +++++++++++++++++++ .../src/market_observer/ftx_observer.java | 81 ++++++++++++++++++ .../market_observer/whitebit_observer.java | 81 ++++++++++++++++++ 6 files changed, 336 insertions(+), 7 deletions(-) create mode 100644 barracuda/src/market_observer/bitfinex_observer.java create mode 100644 barracuda/src/market_observer/bybit_observer.java create mode 100644 barracuda/src/market_observer/ftx_observer.java create mode 100644 barracuda/src/market_observer/whitebit_observer.java diff --git a/barracuda/src/main/Main.java b/barracuda/src/main/Main.java index 8f999492..f1c30ded 100644 --- a/barracuda/src/main/Main.java +++ b/barracuda/src/main/Main.java @@ -38,14 +38,18 @@ private static void refresh_periodically() public static void main(String[] args) { - refresh_interval = 4950; + refresh_interval = 4000; market_observers.add(new bitbay_observer("BTC")); - market_observers.add(new bitbay_observer("LTC")); - market_observers.add(new bitbay_observer("LSK")); - market_observers.add(new bitbay_observer("GAME")); - market_observers.add(new bitbay_observer("REP")); - market_observers.add(new bitbay_observer("PAY")); + market_observers.add(new bybit_observer("BTC")); + market_observers.add(new bitfinex_observer("BTC")); +// market_observers.add(new whitebit_observer("BTC")); +// market_observers.add(new bitbay_observer("LTC")); +// market_observers.add(new bitbay_observer("LSK")); +// market_observers.add(new bitbay_observer("GAME")); +// market_observers.add(new bitbay_observer("REP")); +// market_observers.add(new bitbay_observer("PAY")); + Thread thread = new Thread(Main::refresh_periodically); thread.setDaemon(true); diff --git a/barracuda/src/market_observer/bitbay_observer.java b/barracuda/src/market_observer/bitbay_observer.java index 79d97937..2c6ce5a9 100644 --- a/barracuda/src/market_observer/bitbay_observer.java +++ b/barracuda/src/market_observer/bitbay_observer.java @@ -9,11 +9,12 @@ public class bitbay_observer extends market_observer public bitbay_observer(String currency) { - super(currency, "bitbay", 0.005f); + super(currency, "bitbay", 0.003f); try { currency_url = new URL("https://bitbay.net/API/Public/"+ currency + "/orderbook.json"); update_data(); + print_status(); } catch (MalformedURLException e) { diff --git a/barracuda/src/market_observer/bitfinex_observer.java b/barracuda/src/market_observer/bitfinex_observer.java new file mode 100644 index 00000000..92d1c122 --- /dev/null +++ b/barracuda/src/market_observer/bitfinex_observer.java @@ -0,0 +1,79 @@ +package market_observer; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +public class bitfinex_observer extends market_observer +{ + private URL currency_url; + + public bitfinex_observer(String currency) + { + super(currency, "bitfinex", 0.002f); + try + { + currency_url = new URL("https://api-pub.bitfinex.com/v2/ticker/t"+ currency + "USD"); + update_data(); + print_status(); + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency); + e.printStackTrace(); + } + } + + @Override + public void update_data() + { + try + { + URLConnection conn = currency_url.openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) get_data_from_json_string(line); + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (IOException e) { e.printStackTrace(); } + } + + private void get_data_from_json_string(String json_string) + { +// System.out.println(json_string); +// return; + if(json_string == null) return; + + try + { + int bid_price_start_position = json_string.indexOf('[') + 1; + int bid_amount_start_position = json_string.indexOf(',', bid_price_start_position ) + 1; + int ask_price_start_position = json_string.indexOf(',', bid_amount_start_position) + 1; + int ask_amount_start_position = json_string.indexOf(',', ask_price_start_position ) + 1; + int ask_amount_end_position = json_string.indexOf(',', ask_amount_start_position ) - 1; +// + bid_price = Float.parseFloat( json_string.substring(bid_price_start_position, bid_amount_start_position - 1 ) ); + bid_amount = Float.parseFloat( json_string.substring(bid_amount_start_position, ask_price_start_position - 2 ) ); + + ask_price = Float.parseFloat( json_string.substring(ask_price_start_position, ask_amount_start_position - 1 ) ); + ask_amount = Float.parseFloat( json_string.substring(ask_amount_start_position, ask_amount_end_position ) ); +// +//// System.out.println("bid: " + bid_amount + " ✖️ " + bid_price + "; ask: " + ask_amount + " ✖️ " + ask_price); + } + catch (NumberFormatException ignored){ /* System.out.println(ignored); */ } + + } +} diff --git a/barracuda/src/market_observer/bybit_observer.java b/barracuda/src/market_observer/bybit_observer.java new file mode 100644 index 00000000..2bd70a1d --- /dev/null +++ b/barracuda/src/market_observer/bybit_observer.java @@ -0,0 +1,83 @@ +package market_observer; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +public class bybit_observer extends market_observer +{ + private URL currency_url; + + public bybit_observer(String currency) + { + super(currency, "bybit", 0.0007f); + try + { + currency_url = new URL("https://api.bybit.com/v2/public/orderBook/L2?symbol="+ currency + "USD"); + update_data(); + print_status(); + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency); + e.printStackTrace(); + } + } + + @Override + public void update_data() + { + try + { + URLConnection conn = currency_url.openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) get_data_from_json_string(line); + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (IOException e) { e.printStackTrace(); } + } + + private void get_data_from_json_string(String json_string) + { +// System.out.println(json_string); +// return; + if(json_string == null) return; + + try + { + int bid_price_start_position = json_string.indexOf("\"price\":\"") + 9; + int bid_price_end_position = json_string.indexOf("\",\"size\":", bid_price_start_position ); + int bid_amount_end_position = json_string.indexOf(',', bid_price_end_position + 9); + + int first_sell_position = json_string.indexOf("Sell") - 40; + + int ask_price_start_position = json_string.indexOf("\"price\":\"", first_sell_position ) + 9; + int ask_price_end_position = json_string.indexOf("\",\"size\":", ask_price_start_position ); + int ask_amount_end_position = json_string.indexOf(',', ask_price_end_position + 9); + + bid_price = Float.parseFloat( json_string.substring(bid_price_start_position, bid_price_end_position ) ); + bid_amount = Float.parseFloat( json_string.substring(bid_price_end_position + 9, bid_amount_end_position ) ) / bid_price; + + ask_price = Float.parseFloat( json_string.substring(ask_price_start_position, ask_price_end_position ) ); + ask_amount = Float.parseFloat( json_string.substring(ask_price_end_position + 9, ask_amount_end_position ) ) / ask_price; + +// System.out.println("bid: " + bid_amount + " ✖️ " + bid_price + "; ask: " + ask_amount + " ✖️ " + ask_price); + } + catch (NumberFormatException ignored){ /* System.out.println(ignored); */ } + + } +} diff --git a/barracuda/src/market_observer/ftx_observer.java b/barracuda/src/market_observer/ftx_observer.java new file mode 100644 index 00000000..2257c00d --- /dev/null +++ b/barracuda/src/market_observer/ftx_observer.java @@ -0,0 +1,81 @@ +package market_observer; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +public class ftx_observer extends market_observer +{ + private URL currency_url; + + public ftx_observer(String currency) + { + super(currency, "ftx", 0.0007f); + try + { + currency_url = new URL("https://ftx.com/api//markets/"+ currency + "_USD/orderbook"); + update_data(); + print_status(); + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency); + e.printStackTrace(); + } + } + + @Override + public void update_data() + { + try + { + URLConnection conn = currency_url.openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) get_data_from_json_string(line); + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (IOException e) { e.printStackTrace(); } + } + + private void get_data_from_json_string(String json_string) + { +// System.out.println(json_string); +// return; + if(json_string == null) return; + + try + { + int bid_price_start_position = json_string.indexOf("\"bids\":[[") + 9; + int bid_price_end_position = json_string.indexOf(',', bid_price_start_position ); + int bid_amount_end_position = json_string.indexOf(']', bid_price_end_position ); + + int ask_price_start_position = json_string.indexOf("\"asks\":[[") + 9; + int ask_price_end_position = json_string.indexOf(',', ask_price_start_position ); + int ask_amount_end_position = json_string.indexOf(']', ask_price_end_position ); + + bid_price = Float.parseFloat( json_string.substring(bid_price_start_position, bid_price_end_position ) ); + bid_amount = Float.parseFloat( json_string.substring(bid_price_end_position + 1, bid_amount_end_position ) ); + + ask_price = Float.parseFloat( json_string.substring(ask_price_start_position, ask_price_end_position ) ); + ask_amount = Float.parseFloat( json_string.substring(ask_price_end_position + 1, ask_amount_end_position ) ); + +// System.out.println("bid: " + bid_amount + " ✖️ " + bid_price + "; ask: " + ask_amount + " ✖️ " + ask_price); + } + catch (NumberFormatException ignored){ /* System.out.println(ignored); */ } + + } +} diff --git a/barracuda/src/market_observer/whitebit_observer.java b/barracuda/src/market_observer/whitebit_observer.java new file mode 100644 index 00000000..0b76a281 --- /dev/null +++ b/barracuda/src/market_observer/whitebit_observer.java @@ -0,0 +1,81 @@ +package market_observer; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +public class whitebit_observer extends market_observer +{ + private URL currency_url; + + public whitebit_observer(String currency) + { + super(currency, "whitebit", 0.001f); + try + { + currency_url = new URL("https://whitebit.com/api/v1/public/depth/result?market="+ currency + "_USD&limit=1"); + update_data(); + print_status(); + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency); + e.printStackTrace(); + } + } + + @Override + public void update_data() + { + try + { + URLConnection conn = currency_url.openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) get_data_from_json_string(line); + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (IOException e) { e.printStackTrace(); } + } + + private void get_data_from_json_string(String json_string) + { +// System.out.println(json_string); +// return; + if(json_string == null) return; + + try + { + int bid_price_start_position = json_string.indexOf("\"bids\":[[") + 9; + int bid_price_end_position = json_string.indexOf(',', bid_price_start_position ); + int bid_amount_end_position = json_string.indexOf(']', bid_price_end_position ); + + int ask_price_start_position = json_string.indexOf("\"asks\":[[") + 9; + int ask_price_end_position = json_string.indexOf(',', ask_price_start_position ); + int ask_amount_end_position = json_string.indexOf(']', ask_price_end_position ); + + bid_price = Float.parseFloat( json_string.substring(bid_price_start_position + 1, bid_price_end_position - 1 ) ); + bid_amount = Float.parseFloat( json_string.substring(bid_price_end_position + 2, bid_amount_end_position - 1) ); + + ask_price = Float.parseFloat( json_string.substring(ask_price_start_position + 1, ask_price_end_position - 1) ); + ask_amount = Float.parseFloat( json_string.substring(ask_price_end_position + 2, ask_amount_end_position - 1) ); + +// System.out.println("bid: " + bid_amount + " ✖️ " + bid_price + "; ask: " + ask_amount + " ✖️ " + ask_price); + } + catch (NumberFormatException ignored){ /* System.out.println(ignored); */ } + + } +} From 608ea0687e86ea78cf83bfc5ee901c3f387c08bd Mon Sep 17 00:00:00 2001 From: japko-7 Date: Sat, 9 May 2020 23:55:49 +0200 Subject: [PATCH 4/6] implemented wallet and cross-market operations simulation --- barracuda/src/main/Main.java | 87 ++++++++++++++++++- .../src/market_observer/market_observer.java | 14 ++- 2 files changed, 96 insertions(+), 5 deletions(-) diff --git a/barracuda/src/main/Main.java b/barracuda/src/main/Main.java index f1c30ded..a8b76ab1 100644 --- a/barracuda/src/main/Main.java +++ b/barracuda/src/main/Main.java @@ -9,6 +9,7 @@ public class Main { private static ArrayList market_observers = new ArrayList(); private static int refresh_interval; + private static float wallet; private static void refresh() { @@ -20,6 +21,79 @@ private static void refresh() } } + private static void make_transactions() + { + while (true) make_best_transaction(); + } + + private static void make_best_transaction() + { + float best_amount = 0; + float best_profit = 0; + int best_seller_index = 0; + int best_buyer_index = 0; + + for(int i = 0; i < market_observers.size(); i++) + { + market_observer comparing = market_observers.get(i); + int highest_bid_index = i; + int lowest_ask_index = i; + float highest_bid = comparing.bid_price(); + float lowest_ask = comparing.ask_price(); + + for(int j = 0; j < market_observers.size(); j++) + { + market_observer comparing_2 = market_observers.get(j); + if(comparing.currency() == comparing_2.currency()) + { + if(comparing_2.bid_price() > highest_bid) + { + highest_bid = comparing_2.bid_price(); + highest_bid_index = j; + } + if(comparing_2.ask_price() < lowest_ask) + { + lowest_ask = comparing_2.ask_price(); + lowest_ask_index = j; + } + } + } + + market_observer bidder = market_observers.get(highest_bid_index); + market_observer asker = market_observers.get(lowest_ask_index); + + float current_amount = Math.min(wallet / asker.ask_price(), Math.min(bidder.bid_amount(), asker.ask_amount())); + float current_profit = current_amount * (1 - asker.commission_fee()) * bidder.bid_price() * (1 - bidder.commission_fee()) + - current_amount * asker.ask_price(); + + if(current_profit > best_profit) + { + best_amount = current_amount; + best_profit = current_profit; + best_buyer_index = highest_bid_index; + best_seller_index = lowest_ask_index; + } + + } + + market_observer best_seller = market_observers.get(best_seller_index); + market_observer best_buyer = market_observers.get(best_buyer_index); + + if(best_profit >= 0.00005) + { + wallet += best_profit; + best_seller.apply_buying_transaction(best_amount); // buy from them + best_buyer.apply_selling_transaction(best_amount); // sell them + + System.out.println( + "Buying " + best_amount + " of " + best_seller.currency() + + " for " + best_amount * best_seller.ask_price() + " USD on " + + best_seller.name() + " and selling with a profit of " + best_profit + + " on " + best_buyer.name() + "; current wallet is $" + wallet + ); + } + } + private static void refresh_periodically() { while (true) @@ -38,23 +112,32 @@ private static void refresh_periodically() public static void main(String[] args) { + wallet = 100000; refresh_interval = 4000; market_observers.add(new bitbay_observer("BTC")); market_observers.add(new bybit_observer("BTC")); market_observers.add(new bitfinex_observer("BTC")); // market_observers.add(new whitebit_observer("BTC")); -// market_observers.add(new bitbay_observer("LTC")); + + + market_observers.add(new bitbay_observer("ETH")); + market_observers.add(new bybit_observer("ETH")); + market_observers.add(new bitfinex_observer("ETH")); + // market_observers.add(new bitbay_observer("LSK")); // market_observers.add(new bitbay_observer("GAME")); // market_observers.add(new bitbay_observer("REP")); // market_observers.add(new bitbay_observer("PAY")); - Thread thread = new Thread(Main::refresh_periodically); thread.setDaemon(true); thread.start(); + + make_transactions(); + try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } + } } diff --git a/barracuda/src/market_observer/market_observer.java b/barracuda/src/market_observer/market_observer.java index e13ae5c7..bedfb66d 100644 --- a/barracuda/src/market_observer/market_observer.java +++ b/barracuda/src/market_observer/market_observer.java @@ -3,20 +3,23 @@ public abstract class market_observer { float bid_price = 0, ask_price = 0, bid_amount = 0, ask_amount = 0; - private float commission_rate = 0.005f; + private float commission_fee = 0.005f; private String currency, name; - market_observer(String currency, String name, float commission_rate) + market_observer(String currency, String name, float commission_fee) { this.currency = currency; this.name = name; - this.commission_rate = commission_rate; + this.commission_fee = commission_fee; } public float bid_price(){ return bid_price; } public float ask_price(){ return ask_price; } public float bid_amount(){ return bid_amount; } public float ask_amount(){ return ask_amount; } + public float commission_fee(){ return commission_fee; } + public String currency() { return currency; } + public String name() { return name; } public float spread(){ return (ask_price - bid_price) / bid_price;} public void print_status() @@ -31,5 +34,10 @@ public void print_status() ); } + public void apply_buying_transaction(float amount) + { ask_amount -= amount; } + public void apply_selling_transaction(float amount) + { bid_amount -= amount; } + public abstract void update_data(); } From d43502e1661bce6f70265d0233dcf04f39e24719 Mon Sep 17 00:00:00 2001 From: japko-7 Date: Sun, 7 Jun 2020 02:17:17 +0200 Subject: [PATCH 5/6] =?UTF-8?q?postin=20da=20soluci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- trend_predictor/src/base/data.java | 22 ++ .../src/base/history_provider.java | 110 +++++++++ trend_predictor/src/main/Main.java | 223 ++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 trend_predictor/src/base/data.java create mode 100644 trend_predictor/src/base/history_provider.java create mode 100644 trend_predictor/src/main/Main.java diff --git a/trend_predictor/src/base/data.java b/trend_predictor/src/base/data.java new file mode 100644 index 00000000..7add22c3 --- /dev/null +++ b/trend_predictor/src/base/data.java @@ -0,0 +1,22 @@ +package base; + +public class data +{ + private float price; + private float volume; + + public data() + { + this.price = 0f; + this.volume = 0f; + } + + public data(float price, float volume) + { + this.price = price; + this.volume = volume; + } + + public float price() { return price; } + public float volume() { return volume; } +} diff --git a/trend_predictor/src/base/history_provider.java b/trend_predictor/src/base/history_provider.java new file mode 100644 index 00000000..7827805d --- /dev/null +++ b/trend_predictor/src/base/history_provider.java @@ -0,0 +1,110 @@ +package base; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; + +public class history_provider +{ + private String currency_url; + + public history_provider(String currency) + { + currency_url = "https://api.coingecko.com/api/v3/coins/" + currency + "/history?localization=false&date="; + } + + public data obtain_data(String date) // 23-03-2015 + { + data historical_data = new data(); + try + { + URLConnection conn = new URL(currency_url + date).openConnection(); + try + { + BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + try + { + String line; + if ((line = buffered_reader.readLine()) != null) + { + historical_data = get_data_from_json_string(line); +// System.out.println(data); + } + } + catch (EOFException ignored) { } + + buffered_reader.close(); + } + catch (IOException e) { e.printStackTrace(); } + } + catch (MalformedURLException e) + { + System.out.println("Invalid URL for " + currency_url); + e.printStackTrace(); + } + catch (IOException e) { e.printStackTrace(); } + + return historical_data; + } + + private data get_data_from_json_string(String json_string) + { +// System.out.println(json_string); +// return new data(); + + if(json_string == null) return new data(); + + float price = 0f, volume = 0f; + try + { + int current_price_start_position = json_string.indexOf( "\"current_price\":{" ); + int price_start_position = json_string.indexOf("\"usd\":", current_price_start_position ) + 6; + int price_end_position = json_string.indexOf(',', price_start_position ); + + int current_volume_start_position = json_string.indexOf( "\"total_volume\":{" ); + int volume_start_position = json_string.indexOf("\"usd\":", current_volume_start_position ) + 6; + int volume_end_position = json_string.indexOf(',', volume_start_position ); + + price = Float.parseFloat( json_string.substring(price_start_position, price_end_position ) ); + volume = Float.parseFloat( json_string.substring(volume_start_position, volume_end_position ) ); + } + catch (java.lang.NumberFormatException ignored){ /* System.out.println(ignored); */ } + + return new data(price, volume); + } + + public ArrayList provide_data(String date_from, String date_to) // 23-03-2015 + { + ArrayList historical_data = new ArrayList(); + + try + { + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); // 23-03-2015 + SimpleDateFormat reversed_formatter = new SimpleDateFormat("yyyy-MM-dd"); // 2015-03-23 + Date startDate = formatter.parse(date_from); + Date endDate = formatter.parse(date_to); + LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) + { +// System.out.println(formatter.format(reversed_formatter.parse(date.toString()))); + historical_data.add(obtain_data(formatter.format(reversed_formatter.parse(date.toString())))); + } + + } + catch (ParseException e) { e.printStackTrace(); } + + return historical_data; + } +} diff --git a/trend_predictor/src/main/Main.java b/trend_predictor/src/main/Main.java new file mode 100644 index 00000000..613a7737 --- /dev/null +++ b/trend_predictor/src/main/Main.java @@ -0,0 +1,223 @@ +package main; + +import base.data; +import base.history_provider; +import org.knowm.xchart.*; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.Random; + +public class Main +{ + private static Random generator = new Random(); + private static history_provider btc_provider = new history_provider("bitcoin"); + private static history_provider ltc_provider = new history_provider("litecoin"); + private static history_provider eth_provider = new history_provider("ethereum"); + + public static void draw_chart(OHLCChart chart, ArrayList historical, ArrayList predicted, String date_from, String date_to, String caption) + { + ArrayList xData = new ArrayList(); + ArrayList openData = new ArrayList(); +// ArrayList highData = new ArrayList(); +// ArrayList lowData = new ArrayList(); + ArrayList closeData = new ArrayList(); + ArrayList volumeData = new ArrayList(); + + try + { + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); // 23-03-2015 + SimpleDateFormat reversed_formatter = new SimpleDateFormat("yyyy-MM-dd"); // 2015-03-23 + Date startDate = formatter.parse(date_from); + Date endDate = formatter.parse(date_to); + LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + + int change_index = 0; + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) + { + xData.add(reversed_formatter.parse(date.toString())); + } + + } + catch (ParseException e) { e.printStackTrace(); } + + xData.add(xData.get(xData.size() - 1)); + + openData.add(historical.get(0).price()); + historical.forEach(x -> + { + openData.add(x.price()); + closeData.add(x.price()); + volumeData.add(x.volume()); + }); + predicted.forEach(x -> + { + openData.add(x.price()); + closeData.add(x.price()); + volumeData.add(x.volume()); + }); + + openData.remove(openData.size() - 1); + + chart.addSeries(caption, xData, openData, closeData, openData, closeData, volumeData); + + System.out.println("------------------"); + System.out.println(caption); + System.out.println("FROM: " + date_from); + historical.forEach(x -> System.out.println("price: " + x.price() + "\tvolume: " + x.volume())); + predicted.forEach(x -> System.out.println("price: " + x.price() + "\tvolume: " + x.volume())); + System.out.println("TO: " + date_to); + } + + private static ArrayList values_to_changes(ArrayList values) + { + ArrayList changes = new ArrayList(); + + for (int i = 1; i < values.size(); i++) + { + float price_change = (values.get(i).price() - values.get(i - 1).price()) / values.get(i - 1).price(); + float volume_change = (values.get(i).volume() - values.get(i - 1).volume()) / values.get(i - 1).volume(); + changes.add(new data(price_change, volume_change)); + +// changes.forEach((x)->System.out.printf("p:\t%.2f%%\tv:\t%.2f%%\n", + x.price() * 100, x.volume() * 100)); + } + + return changes; + } + + static ArrayList> generate_prediction(String currency, String base_date_from, String base_date_to, String prediction_end_date) + { + ArrayList> predictions = new ArrayList>(); + ArrayList historical_data; + + switch (currency) + { + case "LTC": + historical_data = ltc_provider.provide_data(base_date_from, base_date_to); + break; + case "ETH": + historical_data = eth_provider.provide_data(base_date_from, base_date_to); + break; + default: // BTC + historical_data = btc_provider.provide_data(base_date_from, base_date_to); + } + + data last_data = historical_data.get(historical_data.size() - 1); + for (int i = 0; i < 100; i++) + predictions.add(generate_prediction(values_to_changes(historical_data), last_data, base_date_to, prediction_end_date)); + + int predictions_size = predictions.size(); + int prediction_size = predictions.get(0).size(); + ArrayList average_prediction = new ArrayList(); + ArrayList median_prediction = new ArrayList(); + ArrayList standard_deviations = new ArrayList(); + + for (int j = 0; j < prediction_size; j++) + { + ArrayList prices = new ArrayList(); + ArrayList volumes = new ArrayList(); + float average_price = 0, average_volume = 0; + float price_deviation = 0, volume_deviation = 0; + + for (int i = 0; i < predictions_size; i++) + { + prices.add(predictions.get(i).get(j).price()); + volumes.add(predictions.get(i).get(j).volume()); + + average_price += predictions.get(i).get(j).price(); + average_volume += predictions.get(i).get(j).volume(); + } + + prices.sort(Comparator.naturalOrder()); + volumes.sort(Comparator.naturalOrder()); + + if(predictions_size % 2 == 0) + { + float median_price = (prices.get(prices.size() / 2) + prices.get(prices.size() / 2 - 1)) / 2; + float median_volume = (volumes.get(volumes.size() / 2) + volumes.get(volumes.size() / 2 - 1)) / 2; + median_prediction.add(new data(median_price, median_volume)); + } + else + { + float median_price = prices.get(prices.size() / 2); + float median_volume = volumes.get(volumes.size() / 2); + median_prediction.add(new data(median_price, median_volume)); + } + + average_price /= predictions_size; + average_volume /= predictions_size; + + for (ArrayList prediction : predictions) + { + price_deviation += (prediction.get(j).price() - average_price) * (prediction.get(j).price() - average_price); + volume_deviation += (prediction.get(j).volume() - average_volume) * (prediction.get(j).volume() - average_volume); + } + + price_deviation /= (predictions_size - 1); + volume_deviation /= (predictions_size - 1); + price_deviation = (float) Math.sqrt(price_deviation); + volume_deviation = (float) Math.sqrt(volume_deviation); + + standard_deviations.add(new data(price_deviation, volume_deviation)); + average_prediction.add(new data(average_price, average_volume)); + } + + OHLCChartBuilder chart_builder = new OHLCChartBuilder(); + chart_builder.height = 600; + chart_builder.width = 800; + chart_builder.title = currency + " from " + base_date_from + " to " + prediction_end_date; + OHLCChart chart = new OHLCChart(chart_builder); + +// draw_chart(chart, historical_data, predictions.get(0), base_date_from, prediction_end_date, "single"); + draw_chart(chart, historical_data, average_prediction, base_date_from, prediction_end_date, "average"); +// draw_chart(chart, historical_data, median_prediction, base_date_from, prediction_end_date, "median"); + + new SwingWrapper(chart).displayChart(); + + System.out.println("standard deviations: "); + standard_deviations.forEach(deviation -> System.out.println("price: " + deviation.price() + "\tvolume: " + deviation.volume())); + + return predictions; + } + + public static ArrayList generate_prediction(ArrayList base, data last, String date_from, String date_to) // 23-03-2015 + { + ArrayList prediction = new ArrayList(); + + try + { + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); // 23-03-2015 + SimpleDateFormat reversed_formatter = new SimpleDateFormat("yyyy-MM-dd"); // 2015-03-23 + Date startDate = formatter.parse(date_from); + Date endDate = formatter.parse(date_to); + LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + + int change_index = 0; + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) + { + change_index = generator.nextInt(base.size()); + float next_price = last.price() * (base.get(change_index).price() + 1); + float next_volume = last.volume() * (base.get(change_index).volume() + 1); + last = new data(next_price, next_volume); + prediction.add(last); + } + + } + catch (ParseException e) { e.printStackTrace(); } + + return prediction; + } + + public static void main(String[] args) throws IOException + { + generate_prediction("BTC", "23-03-2015", "28-03-2015", "30-04-2015"); + } +} From 3f7f36944d2db4d6af6edeb572276af7ae1501f8 Mon Sep 17 00:00:00 2001 From: japko-7 Date: Sun, 7 Jun 2020 02:50:42 +0200 Subject: [PATCH 6/6] minor improvements, including data provider overload --- trend_predictor/src/base/history_provider.java | 15 ++++++++++++++- trend_predictor/src/main/Main.java | 13 ++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/trend_predictor/src/base/history_provider.java b/trend_predictor/src/base/history_provider.java index 7827805d..e9b72493 100644 --- a/trend_predictor/src/base/history_provider.java +++ b/trend_predictor/src/base/history_provider.java @@ -7,6 +7,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.sql.Time; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -96,14 +97,26 @@ public ArrayList provide_data(String date_from, String date_to) // 23-03-2 LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + int counter = 0; + long start_time = System.currentTimeMillis(); for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { // System.out.println(formatter.format(reversed_formatter.parse(date.toString()))); historical_data.add(obtain_data(formatter.format(reversed_formatter.parse(date.toString())))); + +// counter ++; +// if(counter > 98) +// { +// while (System.currentTimeMillis() < start_time + 100 * 1000){} +// start_time = System.currentTimeMillis(); +// counter = 0; +// } + + Thread.sleep(600); } } - catch (ParseException e) { e.printStackTrace(); } + catch (ParseException | InterruptedException e) { e.printStackTrace(); } return historical_data; } diff --git a/trend_predictor/src/main/Main.java b/trend_predictor/src/main/Main.java index 613a7737..3d65144b 100644 --- a/trend_predictor/src/main/Main.java +++ b/trend_predictor/src/main/Main.java @@ -48,7 +48,7 @@ public static void draw_chart(OHLCChart chart, ArrayList historical, Array } catch (ParseException e) { e.printStackTrace(); } - xData.add(xData.get(xData.size() - 1)); +// xData.add(xData.get(xData.size() - 1)); openData.add(historical.get(0).price()); historical.forEach(x -> @@ -65,6 +65,9 @@ public static void draw_chart(OHLCChart chart, ArrayList historical, Array }); openData.remove(openData.size() - 1); + openData.remove(openData.size() - 1); + closeData.remove(closeData.size() - 1); + volumeData.remove(volumeData.size() - 1); chart.addSeries(caption, xData, openData, closeData, openData, closeData, volumeData); @@ -175,9 +178,9 @@ static ArrayList> generate_prediction(String currency, String ba chart_builder.title = currency + " from " + base_date_from + " to " + prediction_end_date; OHLCChart chart = new OHLCChart(chart_builder); -// draw_chart(chart, historical_data, predictions.get(0), base_date_from, prediction_end_date, "single"); + draw_chart(chart, historical_data, predictions.get(0), base_date_from, prediction_end_date, "single"); draw_chart(chart, historical_data, average_prediction, base_date_from, prediction_end_date, "average"); -// draw_chart(chart, historical_data, median_prediction, base_date_from, prediction_end_date, "median"); + draw_chart(chart, historical_data, median_prediction, base_date_from, prediction_end_date, "median"); new SwingWrapper(chart).displayChart(); @@ -216,8 +219,8 @@ public static ArrayList generate_prediction(ArrayList base, data las return prediction; } - public static void main(String[] args) throws IOException + public static void main(String[] args) { - generate_prediction("BTC", "23-03-2015", "28-03-2015", "30-04-2015"); + generate_prediction("BTC", "23-08-2015", "28-12-2015", "30-01-2016"); } }