aboutsummaryrefslogblamecommitdiff
path: root/script.py
blob: c5ac4aa9ba42630ebe1cfeeaaad1e8210d239443 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
           

                                        
 





                                     
               








                              



                                           
                        
                               

                       
                                 

                                              

                                                
                 






                                                         





                                                                   
        
                                                                                                  
                                                                    

                              
                                                                                                      
                                                                        
                                  

                                                               
 







                                                       








                                                                                   
                                                                                            








                                                                                                    
                                                                                           








                                                                                                                        















                                                                  
                     

                                        
             

































































                                                                                                

                                                                      


                                              
 
                                       
                                                                
import ccxt
# Put your poloniex api key in market.py
from market import market

def static_var(varname, value):
    def decorate(func):
        setattr(func, varname, value)
        return func
    return decorate

max_digits = 18

repartition_pertenthousand = {
        "BTC":  2857,
        "ZEC":  3701,
        "DOGE": 1805,
        "DGB":  1015,
        "SC":    623,
        }


def formatted_price(value):
    return round(value / 10**max_digits, 8)

@static_var("cache", {})
def get_ticker(c1, c2, market):
    def invert(ticker):
        return {
                "inverted": True,
                "bid": float(1/ticker["ask"]),
                "ask": float(1/ticker["bid"]),
                "bidA": float(1/ticker["askA"]),
                "askA": float(1/ticker["bidA"]),
                }
    def augment_ticker(ticker):
        # FIXME: need to do better than just a multiplier
        ticker.update({
            "inverted": False,
            "bidA": ticker["bid"] * 0.99,
            "askA": ticker["ask"] * 1.01,
            })

    if (c1, c2, market.__class__) in get_ticker.cache:
        return get_ticker.cache[(c1, c2, market.__class__)]
    if (c2, c1, market.__class__) in get_ticker.cache:
        return invert(get_ticker.cache[(c2, c1, market.__class__)])

    try:
        get_ticker.cache[(c1, c2, market.__class__)] = market.fetch_ticker("{}/{}".format(c1, c2))
        augment_ticker(get_ticker.cache[(c1, c2, market.__class__)])
    except ccxt.ExchangeError:
        try:
            get_ticker.cache[(c2, c1, market.__class__)] = market.fetch_ticker("{}/{}".format(c2, c1))
            augment_ticker(get_ticker.cache[(c2, c1, market.__class__)])
        except ccxt.ExchangeError:
            get_ticker.cache[(c1, c2, market.__class__)] = None
    return get_ticker(c1, c2, market)

def fetch_balances(market):
    balances = {}
    fetched_balance = market.fetch_balance()
    for key, value in fetched_balance["total"].items():
        if value > 0:
            balances[key] = int(value * 10**max_digits)
    return balances

def assets_value(assets, market, base_currency="BTC"):
    repartition_in_base_currency = {}
    for currency, asset_value in assets.items():
        if currency == base_currency:
            repartition_in_base_currency[currency] = asset_value
        else:
            asset_ticker = get_ticker(currency, base_currency, market)
            if asset_ticker is None:
                raise Exception("This asset is not available in the chosen market")
            repartition_in_base_currency[currency] = int(asset_ticker["bidA"] * asset_value)
    return repartition_in_base_currency

def dispatch_assets(base_currency_value, repartition_pertenthousand, market, base_currency="BTC"):
    sum_pertenthousand = sum([v for k, v in repartition_pertenthousand.items()])
    repartition_in_base_currency = {}
    for currency, ptt in repartition_pertenthousand.items():
        repartition_in_base_currency[currency] = int(ptt * base_currency_value / sum_pertenthousand)
    return repartition_in_base_currency

def compute_moves(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
    value_in_base = assets_value(current_assets, market, base_currency=base_currency)
    total_base_value = sum([ v for k, v in value_in_base.items()])

    new_repartition = dispatch_assets(total_base_value, repartition_pertenthousand, market, base_currency=base_currency)
    mouvements = {}

    for key in set(value_in_base.keys()).union(set(new_repartition.keys())):
        mouvements[key] = value_in_base.get(key, 0) - new_repartition.get(key, 0)

    return mouvements

def compute_order(currency, value, market, base_currency="BTC"):
    if currency == base_currency or value == 0:
        return [None, 0, False]

    asset_ticker = get_ticker(currency, base_currency, market)
    if asset_ticker["inverted"]:
        asset_ticker = get_ticker(base_currency, currency, market)
        if value > 0:
            rate = asset_ticker["askA"]
            return ["buy", rate, True]
        else:
            rate = asset_ticker["bidA"]
            return ["sell", rate, True]
    else:
        if value > 0:
            rate = asset_ticker["bidA"]
            return ["sell", rate, False]
        else:
            rate = asset_ticker["askA"]
            return ["buy", rate, False]

def make_order(currency, value, market, base_currency="BTC"):
    action, rate, inverted = compute_order(currency, value, market, base_currency=base_currency)
    amount = formatted_price(abs(value))
    if not inverted:
        symbol = "{}/{}".format(currency, base_currency)
    else:
        symbol = "{}/{}".format(base_currency, currency)
    return market.create_order(symbol, 'limit', action, amount, price=rate)

def make_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
    mouvements = compute_moves(
            current_assets,
            repartition_pertenthousand,
            market,
            base_currency=base_currency)

    results = []
    for currency, value in sorted(mouvements.items(), key=lambda x: x[1]):
        # FIXME: wait for sales to finish
        results.append(make_order(currency, value, market, base_currency=base_currency))
    return results

def print_assets(assets, indent="", market=None, base_currency="BTC"):
    if market is not None:
        format_string = "{}{} {} ({} {})"
    else:
        format_string = "{}{} {}"
        base_currency_price = 0

    for currency, value in assets.items():
        if market is not None:
            asset_ticker = get_ticker(currency, base_currency, market)
            base_currency_price = asset_ticker["bidA"] * value
        print(format_string.format(
            indent,
            formatted_price(value),
            currency,
            formatted_price(base_currency_price),
            base_currency))

def print_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
    mouvements = compute_moves(
            current_assets,
            repartition_pertenthousand,
            market,
            base_currency=base_currency)

    for currency, value in mouvements.items():
        action, rate, inverted = compute_order(
                currency,
                value,
                market,
                base_currency=base_currency)
        if action is not None:
            currency_price = int(value / rate)

            if not inverted:
                c1, c2 = [base_currency, currency]
                v1, v2 = [value, currency_price]
            else:
                c1, c2 = [currency, base_currency]
                v1, v2 = [currency_price, value]

            print("need to {} {} {}'s worth of {}, i.e. {} {}".format(
                action,
                formatted_price(abs(v1)), c1,
                c2,
                formatted_price(abs(v2)), c2))

current_assets = fetch_balances(market)
print_orders(current_assets, repartition_pertenthousand, market)