#!/usr/bin/python
import btceapi
import os
from Queue import Queue
import matplotlib.mlab as mlab
import time
import numpy as np
import decimal
import logging
from trend import Trend

home = os.getenv("HOME")
pair = "btc_usd"
key_file = "%s/key.txt" % home
live_trades = False 
slope_counter=0
bought_flag = False
trend = None

logging.basicConfig(
    format='%(asctime)s:%(name)s:%(levelname)s: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S', filename='%s/bot.log' % home, level=logging.DEBUG
)
logger = logging.getLogger()


def moving_average(x, n, type='simple'):
    """
    compute an n period moving average.

    type is 'simple' | 'exponential'

    """
    x = np.asarray(x)
    if type == 'simple':
        weights = np.ones(n)
    else:
        weights = np.exp(np.linspace(-1., 0., n))

    weights /= weights.sum()

    a = np.convolve(x, weights, mode='full')[:len(x)]
    a[:n] = a[n]
    return a


def relative_strength(prices, n=6):
    """
    compute the n period relative strength indicator
    http://stockcharts.com/school/doku.php?id=chart_school:glossary_r#relativestrengthindex
    http://www.investopedia.com/terms/r/rsi.asp
    """

    deltas = np.diff(prices)
    seed = deltas[:n+1]
    up = seed[seed >= 0].sum()/n
    down = -seed[seed < 0].sum()/n
    rs = up/down
    rsi = np.zeros_like(prices)
    rsi[:n] = 100. - 100./(1. + rs)

    for i in range(n, len(prices)):
        delta = deltas[i - 1]  # cause the diff is 1 shorter

        if delta > 0:
            upval = delta
            downval = 0.
        else:
            upval = 0.
            downval = -delta

        up = (up*(n - 1) + upval)/n
        down = (down*(n - 1) + downval)/n

        rs = up/down
        rsi[i] = 100. - 100./(1. + rs)

    return rsi


def moving_average_convergence(x, nslow=26, nfast=12):
    """
    compute the MACD (Moving Average Convergence/Divergence) using a fast and
    slow exponential moving avg' return value is emaslow, emafast, macd
    which are len(x) arrays
    """
    emaslow = moving_average(x, nslow, type='exponential')
    emafast = moving_average(x, nfast, type='exponential')
    return emaslow, emafast, emafast - emaslow


def _attemptBuy(price, amount=0):
    handler = btceapi.KeyHandler(key_file)
    key = handler.getKeys()[0]
    api = btceapi.TradeAPI(key, handler)
    curr1, curr2 = pair.split("_")

    if not live_trades:
        return 1
    conn = btceapi.BTCEConnection()
    info = api.getInfo(conn)
    # Limit order to what we can afford to buy.
    available = getattr(info, "balance_" + curr2)
    buy_amount = available / price
    if buy_amount > decimal.Decimal(0.01):
        # Limit order to what we can afford to buy.
        logger.info("attempting to buy %s at %s" % (
            buy_amount, price))
        try:
            r = api.trade(pair, "buy", price, buy_amount, conn)
        except Exception as e:
            logger.error(e)
        if r.order_id == 0:
            logger.info("Received %s" % (r.received))
        else:
            logger.info("Payment wasn't fulfiled, waiting 3 sec")
            time.sleep(3)
            api.cancelOrder(r.order_id)
            logger.info("canceling order")
            # If the order didn't fill completely, cancel the remaining order
    else:
        conn.close()
        return False
    conn.close()
    return r.order_id

def _print_available():
    handler = btceapi.KeyHandler(key_file)
    key = handler.getKeys()[0]
    api = btceapi.TradeAPI(key, handler)
    curr1, curr2 = pair.split("_")

    conn = btceapi.BTCEConnection()
    info = api.getInfo(conn)
    available = getattr(info, "balance_" + curr2)
    logger.info("available money:%s usd" % available)
    conn.close()

def _attemptSell(price, amount=0):
    handler = btceapi.KeyHandler(key_file)
    key = handler.getKeys()[0]
    api = btceapi.TradeAPI(key, handler)
    curr1, curr2 = pair.split("_")

    # Limit order to what we can afford to buy.
    # Limit order to what we can afford to buy.
    if not live_trades:
        return 1
    conn = btceapi.BTCEConnection()
    info = api.getInfo(conn)
    available = getattr(info, "balance_" + curr1)
    buy_amount = available
    if buy_amount > decimal.Decimal(0.01):
        logger.info("attempting to sell %s at %s" % (
            buy_amount, price))
        try:
            r = api.trade(pair, "sell", price, buy_amount, conn)
        except Exception as e:
            logger.error(e)
        if r.order_id == 0:
            logger.info("sold %s" % (r.received))
        else:
            logger.info("Payment wasn't fulfiled, waiting 3 sec")
            time.sleep(3)
            api.cancelOrder(r.order_id)
            logger.info("canceling order")
    else:
        conn.close()
        return False

        # If the order didn't fill completely, cancel the remaining order
    conn.close()
    return r.order_id
try:
    while 1:
        try:
            #_print_available()
            fh = open("%s/git/btc.csv" % home, 'r')
            r = mlab.csv2rec(fh)
            fh.close()
            r.sort()
            prices = r.close
            volume = np.average(
                [np.sum(
                    r.volume[-4:-1]), np.sum(r.volume[-5:-9]), np.sum(
                        r.volume[-10:-14])]
            )
            buy_volume = np.average(
                [np.sum(
                    r.buy_vol[-4:-1]), np.sum(r.buy_vol[-5:-9]), np.sum(
                        r.buy_vol[-10:-14])]
            )
            sell_volume = np.average(
                [np.sum(
                    r.sell_vol[-4:-1]), np.sum(r.sell_vol[-5:-9]), np.sum(
                        r.sell_vol[-10:-14])]
            )
            logger.info("buy_volume is: %s sell_volume is: %s" % (buy_volume, sell_volume))
            depth = btceapi.getDepth(pair)
            buy_orders15 = [[b[1], b[0]] for b in depth[1][:15]]
            buy_orders_margin = []
            buy_orders30 = [[b[1], b[0]] for b in depth[1][:30]]
            sell_orders15 = [[s[1], s[0]] for s in depth[0][:15]]
            sell_orders30 = [[s[1], s[0]] for s in depth[0][:30]]
            masterofsell = max([[s[1], s[0]] for s in depth[0][:25]])
            masterofbuy = max([[b[1], b[0]] for b in depth[1][:25]])

            logger.info("buy orders15: %s sell orders15: %s, buy orders25: %s sell orders25: %s" % (sum(map(lambda x:x[0], buy_orders15)), sum(map(lambda x:x[0],sell_orders15)),
                                                                                                    sum(map(lambda x:x[0], buy_orders30)), sum(map(lambda x:x[0],sell_orders30))))
            last = None
            if sum(map(lambda x:x[0], buy_orders30)) < buy_volume*10:
                logger.info("no buy margin")
                buy_orders_margin = [masterofbuy]
            else:
                while sum(map(lambda x:x[0],buy_orders30)) > buy_volume*10:
                    last = buy_orders30.pop()
                buy_orders_margin = buy_orders30
                buy_orders_margin.append(last)
            last = None
            if sum(map(lambda x:x[0],sell_orders30)) < sell_volume*10:
                logger.info("no sell margin")
                sell_orders_margin = [masterofsell]
            else:
                while sum(map(lambda x:x[0],sell_orders30)) > sell_volume*10:
                    last = sell_orders30.pop()
                sell_orders_margin = sell_orders30
                sell_orders_margin.append(last)
            if trend == None:
                trend = Trend(Queue, buy_orders_margin[-1], sell_orders_margin[-1])

            trend.add(buy_orders_margin[-1], sell_orders_margin[-1])
            trend.calculate_trend()
            logger.info("Trend is: %s" % float(trend.trend))
            logger.info(trend.qBuy.queue)
            logger.info(trend.qSell.queue)

            logger.info("buy margin price:%s, amount:%s, sell margin price:%s, amount:%s" % (buy_orders_margin[-1][1], buy_orders_margin[-1][0], sell_orders_margin[-1][1], sell_orders_margin[-1][0]))
            candle_slope = np.average(prices[-5:-1])-np.average(
                prices[-10:-6])
            if candle_slope < 0:
                slope_counter += 1
            else:
                slope_counter -= 1

            if slope_counter < 0:
                slope_counter = 0
            logger.info("current candle slope is:%s slope_counter:%s" % (candle_slope, slope_counter))
            logger.info("last price: %s" % (prices[-1]))
            if candle_slope > 0 and bought_flag == False and live_trades == True:
                counter = 0
                slope_counter = 0
                while counter <= 3:
                    logger.info("buy at: %s" % (prices[-1] + counter*0.3))
                    status = _attemptBuy(decimal.Decimal(prices[-1] + counter*0.3))
                    if status == 0 or live_trades == False:
                        bought_flag = True
                        break
                    counter += 1
            if slope_counter > 1 and bought_flag == True and live_trades == True:
                counter = 0
                while counter <= 3:
                    logger.info("sell at %s" % (prices[-1] - counter*0.3))
                    status = _attemptSell(decimal.Decimal(prices[-1] - counter*0.3))
                    if status == 0 or live_trades == False:
                        bought_flag= False
                        break
                    counter += 1
        except:
            pass
        # you can do anything else you prefer in this loop while
        # the bot is running in the background
        time.sleep(5)

except KeyboardInterrupt:
    print "Stopping..."
finally:
    print "stopped"
