import datetime, requests
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import json, collections, os

UTC_OFFSET = -14400 # Local offset from UTC
START_DATE = "2016-01-01" # Day to start chat
TMP_DIR = "/tmp" # Writable temp directory, without trailing slash

def unix_to_date(unix_timestamp):
    """ Convert a Unix timestamp (in UTC) to the corresponding Date object """
    return datetime.datetime.utcfromtimestamp(unix_timestamp).strftime('%Y-%m-%d-%H')

def pnx_average(poloniex_price, day):
    """ Take the Poloniex unweighted average price for a given day (6 data points)"""
    total = 0.0
    for hour in range(0, 24, 4):
        formatted_date = day + "-" + format(hour, '02d')
        if not formatted_date in poloniex_price:
            return 0.0
        total += poloniex_price[formatted_date]
    return total/6.0


def zero_to_nan(values):
    """Replace every 0 with 'nan' and return a copy."""
    return [float('nan') if x==0 else x for x in values]

start_unix_utc = int(datetime.datetime.strptime(START_DATE, '%Y-%m-%d').strftime("%s")) + UTC_OFFSET

# Download market data if not exists
if not os.path.exists(TMP_DIR + "/btc_eth"):
    open(TMP_DIR + "/btc_eth", "w").write(requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=BTC_ETH&start=" + str(start_unix_utc) + "&end=9999999999&period=14400").text)
btc_eth_raw = json.loads(open(TMP_DIR + "/btc_eth").read())
if not os.path.exists(TMP_DIR + "/btc_etc"):
    open(TMP_DIR + "/btc_etc", "w").write(requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=BTC_ETC&start=" + str(start_unix_utc) + "&end=9999999999&period=14400").text)
btc_etc_raw = json.loads(open(TMP_DIR + "/btc_etc").read())
if not os.path.exists(TMP_DIR + "/btc_usd"):
    open(TMP_DIR + "/btc_usd", "w").write(requests.get("http://api.coindesk.com/v1/bpi/historical/close.json?start=" + START_DATE + "&end=2018-01-01").text)
btc_usd = json.loads(open(TMP_DIR + "/btc_usd").read(), object_pairs_hook=collections.OrderedDict)

btc_eth_all = dict([(unix_to_date(int(x['date'])), float(x['weightedAverage'])) for x in btc_eth_raw])
btc_etc_all = dict([(unix_to_date(int(x['date'])), float(x['weightedAverage'])) for x in btc_etc_raw])

dates = []
eth_prices = []
etc_prices = []
btc_prices = []

for day in btc_usd['bpi']:
    # Bitcoin prices
    dates += [datetime.datetime.strptime(day + "-12", '%Y-%m-%d-%H')]
    eth_prices += [pnx_average(btc_eth_all, day)]
    etc_prices += [pnx_average(btc_etc_all, day)]
    btc_prices += [btc_usd['bpi'][day]]

ethc_prices = [0.0 if y == 0.0 else x + y for x, y in zip(eth_prices, etc_prices)]

def graph_all(eth_prices, etc_prices, ethc_prices, Y_MAX, y_label):
    ethc_line, = plt.plot_date(dates, zero_to_nan(ethc_prices), label="ETH+ETC", fmt="b-")
    eth_line, = plt.plot_date(dates, eth_prices, label="ETH", fmt="g-")
    etc_line, = plt.plot_date(dates, zero_to_nan(etc_prices), label="ETC", fmt="r-")
    line_date = datetime.datetime.strptime("2016-10-18-12", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='g')
    plt.text(line_date + datetime.timedelta(days=-5),Y_MAX * .25,'DoS Fork 1',rotation=90)
    line_date = datetime.datetime.strptime("2016-11-22-15", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='g')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'DoS Fork 2',rotation=90)
    line_date = datetime.datetime.strptime("2016-10-25-04", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='r')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'ETC DoS Fork',rotation=90)
    line_date = datetime.datetime.strptime("2016-06-17-03", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='b')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'DAO Attack',rotation=90)
    line_date = datetime.datetime.strptime("2016-04-30-00", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='b')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'DAO Announced',rotation=90)
    line_date = datetime.datetime.strptime("2016-07-20-15", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='b')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'DAO Fork',rotation=90)
    line_date = datetime.datetime.strptime("2017-01-13-20", '%Y-%m-%d-%H')
    plt.axvline(line_date, color='red')
    plt.text(line_date + datetime.timedelta(days=2),Y_MAX * .25,'ETC DieHard Fork',rotation=90)
    plt.title("Ethereum and Forks Market Response", fontsize=22)
    plt.xlabel("Date", fontsize=18)
    plt.ylabel(y_label, fontsize=18)
    plt.legend(handles=[ethc_line, eth_line, etc_line])
    #plt.gca().set_yscale('log') # Uncomment these two lines for log scale
    #plt.ylim(0, Y_MAX)
    plt.show()

eth_usd = [0.0 if y == 0.0 else x * y for x, y in zip(btc_prices, eth_prices)]
etc_usd = [0.0 if y == 0.0 else x * y for x, y in zip(btc_prices, etc_prices)]
ethc_usd = [0.0 if y == 0.0 else x * y for x, y in zip(btc_prices, ethc_prices)]
graph_all(eth_usd, etc_usd, ethc_usd, 25, "Price (USD)")
graph_all(eth_prices, etc_prices, ethc_prices, .035, "Price (BTC)")

eth_then_ethc_usd = [x if y == 0.0 else y for x, y in zip(eth_usd, ethc_usd)]
plt.plot_date(dates, zero_to_nan(eth_then_ethc_usd), fmt="b-")
plt.title("Forks as a Currency - Holder Perspective", fontsize=22)
plt.xlabel("Date", fontsize=18)
plt.ylabel("Price (USD)", fontsize=18)
plt.show()