diff --git a/barracuda/src/main/Main.java b/barracuda/src/main/Main.java new file mode 100644 index 00000000..a8b76ab1 --- /dev/null +++ b/barracuda/src/main/Main.java @@ -0,0 +1,143 @@ +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 float wallet; + + 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 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) + { + refresh(); + try + { + Thread.sleep(refresh_interval); + } + catch(InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + } + } + + 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("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/bitbay_observer.java b/barracuda/src/market_observer/bitbay_observer.java new file mode 100644 index 00000000..2c6ce5a9 --- /dev/null +++ b/barracuda/src/market_observer/bitbay_observer.java @@ -0,0 +1,76 @@ +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", 0.003f); + try + { + currency_url = new URL("https://bitbay.net/API/Public/"+ currency + "/orderbook.json"); + 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 (java.lang.NumberFormatException ignored){ /* System.out.println(ignored); */ } + + } +} 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/market_observer.java b/barracuda/src/market_observer/market_observer.java new file mode 100644 index 00000000..bedfb66d --- /dev/null +++ b/barracuda/src/market_observer/market_observer.java @@ -0,0 +1,43 @@ +package market_observer; + +public abstract class market_observer +{ + float bid_price = 0, ask_price = 0, bid_amount = 0, ask_amount = 0; + private float commission_fee = 0.005f; + private String currency, name; + + market_observer(String currency, String name, float commission_fee) + { + this.currency = currency; + this.name = name; + 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() + { + System.out.println + ( + currency + " @ " + + name + ": bid = " + + bid_amount + " ✖️ " + bid_price + ", ask = " + + ask_amount + " ✖️ " + ask_price + ", spread = " + + String.format("%.02f", 100 * spread()) + "%" + ); + } + + 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(); +} 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); */ } + + } +} 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..e9b72493 --- /dev/null +++ b/trend_predictor/src/base/history_provider.java @@ -0,0 +1,123 @@ +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.sql.Time; +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(); + + 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 | InterruptedException 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..3d65144b --- /dev/null +++ b/trend_predictor/src/main/Main.java @@ -0,0 +1,226 @@ +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); + openData.remove(openData.size() - 1); + closeData.remove(closeData.size() - 1); + volumeData.remove(volumeData.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) + { + generate_prediction("BTC", "23-08-2015", "28-12-2015", "30-01-2016"); + } +}