Beispiel #1
0
def determine_maximum_volume_by_balance(pair_id, deal_type, volume, price,
                                        balance):
    """
    :param pair_id:
    :param deal_type:
    :param volume:
    :param price:
    :param balance:
    :return: Decimal object representing exact volume
    """

    base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

    if deal_type == DEAL_TYPE.SELL:
        # What is maximum volume we can SELL at exchange
        if not balance.do_we_have_enough(dst_currency_id, volume):
            volume = balance.available_balance[dst_currency_id]
    elif deal_type == DEAL_TYPE.BUY:
        # what is maximum volume we can buy at exchange
        if not balance.do_we_have_enough(base_currency_id, volume * price):
            volume = (MAX_VOLUME_COEFFICIENT *
                      balance.available_balance[base_currency_id]) / price
    else:

        assert deal_type not in [DEAL_TYPE.BUY, DEAL_TYPE.SELL]

    return volume
Beispiel #2
0
def compute_loss(trades_to_order_by_pair):

    orders_by_arbitrage_id = defaultdict(list)
    # 1 stage group by arbitrage id
    for order, trades in trades_to_order_by_pair:
        orders_by_arbitrage_id[order.arbitrage_id].append((order, trades))

    orders_by_pair = defaultdict(list)

    cnt = 0
    for arbitrage_id in orders_by_arbitrage_id:
        if len(orders_by_arbitrage_id[arbitrage_id]) != 1:
            continue
        order, trades_list = orders_by_arbitrage_id[arbitrage_id][0]
        msg = "can't find pair order - {o}".format(o=order)
        log_to_file(msg,
                    "missing_" + get_pair_name_by_id(order.pair_id) + ".txt")
        cnt += 1
        orders_by_pair[order.pair_id].append((order, trades_list))

    loss_details = defaultdict(list)
    loss_details_total = Counter()

    for pair_id in orders_by_pair:
        loss_by_coin, loss_by_base_coin = compute_loss_by_pair(
            orders_by_pair[pair_id])
        base_currency_id, dst_currency_id = split_currency_pairs(pair_id)
        loss_details[base_currency_id].append(
            LossDetails(base_currency_id, dst_currency_id, pair_id,
                        loss_by_coin, loss_by_base_coin))

        loss_details_total[base_currency_id] += loss_by_base_coin

    return loss_details, loss_details_total
Beispiel #3
0
    def do_we_have_enough_by_pair(self, pair_id, exchange_id, volume, price):

        # i.e. we are going to BUY volume of dst_currency by price
        # using base_currency so we have to adjust volume

        base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

        return self.do_we_have_enough(base_currency_id, exchange_id, volume * price)
Beispiel #4
0
    def subtract_balance_by_pair(self, order_book, volume, price):
        # i.e. we SELL dst_currency_id for src_currency_id
        src_currency_id, dst_currency_id = split_currency_pairs(order_book.pair_id)
        self.subtract_balance(dst_currency_id, order_book.exchange_id, volume)

        self.add_balance(src_currency_id, order_book.exchange_id, volume * price) # <<<==== bitcoin!

        self.update_time(order_book.exchange_id, order_book.timest)
Beispiel #5
0
def round_volume_by_huobi_rules(volume, pair_id):
    pair_name = get_currency_pair_to_huobi(pair_id)
    base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

    if pair_name in PRECISION_NUMBER[base_currency_id]:
        return truncate_float(volume, PRECISION_NUMBER[base_currency_id][pair_name])

    return volume
Beispiel #6
0
def compute_min_cap_from_ticker(pair_id, ticker):
    min_price = DECIMAL_ZERO

    if ticker is not None:
        min_price = max(min_price, ticker.ask)

    base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

    if min_price != DECIMAL_ZERO:
        return MIN_VOLUME_COEFFICIENT[base_currency_id] / min_price

    return DECIMAL_ZERO
Beispiel #7
0
def determine_minimum_volume(first_order_book, second_order_book,
                             balance_state):
    """
        we are going to SELL something at first exchange
        we are going to BUY something at second exchange using BASE_CURRENCY

        This method determine maximum available volume of DST_CURRENCY on 1ST exchanges
        This method determine maximum available volume according to amount of available BASE_CURRENCY on 2ND exchanges

    :param first_order_book:
    :param second_order_book:
    :param balance_state:
    :return:    Decimal object representing exact number
    """

    # 1st stage: What is minimum amount of volume according to order book
    min_volume = min(first_order_book.bid[FIRST].volume,
                     second_order_book.ask[LAST].volume)
    if min_volume <= 0:
        msg = "determine_minimum_volume - something severely wrong - NEGATIVE min price: {pr}".format(
            pr=min_volume)
        print_to_console(msg, LOG_ALL_ERRORS)
        log_to_file(msg, ERROR_LOG_FILE_NAME)

        assert min_volume <= 0

    base_currency_id, dst_currency_id = split_currency_pairs(
        first_order_book.pair_id)

    # 2nd stage: What is maximum volume we can SELL at first exchange
    if not balance_state.do_we_have_enough(
            dst_currency_id, first_order_book.exchange_id, min_volume):
        min_volume = balance_state.get_available_volume_by_currency(
            dst_currency_id, first_order_book.exchange_id)

    # 3rd stage: what is maximum volume we can buy
    if not balance_state.do_we_have_enough_by_pair(
            first_order_book.pair_id, second_order_book.exchange_id,
            min_volume, second_order_book.ask[LAST].price):
        min_volume = (MAX_VOLUME_COEFFICIENT *
                      balance_state.get_available_volume_by_currency(
                          base_currency_id, second_order_book.exchange_id)
                      ) / second_order_book.ask[LAST].price

    return min_volume
Beispiel #8
0
def compute_new_min_cap_from_tickers(pair_id, tickers):
    min_price = DECIMAL_ZERO

    for ticker in tickers:
        if ticker is not None:
            try:
                # FIXME NOTE:   in case of errors we may get string with error instead of Ticker object
                #               need to fix process_async_to_list at ConnectionPool
                min_price = max(min_price, ticker.ask)
            except:
                msg = "Msg bad ticker value = {}!".format(ticker)
                log_to_file(msg, ERROR_LOG_FILE_NAME)

    base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

    if min_price != DECIMAL_ZERO:
        return MIN_VOLUME_COEFFICIENT[base_currency_id] / min_price

    return DECIMAL_ZERO
Beispiel #9
0
def adjust_currency_balance(first_order_book, second_order_book, threshold,
                            balance_threshold, action_to_perform,
                            balance_state, deal_cap, type_of_deal, worker_pool,
                            msg_queue):
    deal_status = STATUS.FAILURE, None

    pair_id = first_order_book.pair_id
    src_currency_id, dst_currency_id = split_currency_pairs(pair_id)
    src_exchange_id = first_order_book.exchange_id
    dst_exchange_id = second_order_book.exchange_id

    if balance_state.is_there_disbalance(dst_currency_id, src_exchange_id, dst_exchange_id, balance_threshold) and \
            is_no_pending_order(pair_id, src_exchange_id, dst_exchange_id):

        max_volume = Decimal(0.5) * abs(
            balance_state.get_available_volume_by_currency(
                dst_currency_id, dst_exchange_id) - balance_state.
            get_available_volume_by_currency(dst_currency_id, src_exchange_id))

        # FIXME NOTE: side effect here
        deal_cap.update_max_volume_cap(max_volume)

        log_currency_disbalance_present(src_exchange_id, dst_exchange_id,
                                        pair_id, dst_currency_id,
                                        balance_threshold, max_volume,
                                        threshold)

        deal_status = search_for_arbitrage(first_order_book, second_order_book,
                                           threshold, balance_threshold,
                                           action_to_perform, balance_state,
                                           deal_cap, type_of_deal, worker_pool,
                                           msg_queue)
    else:
        log_currency_disbalance_heart_beat(src_exchange_id, dst_exchange_id,
                                           dst_currency_id, balance_threshold)

    return deal_status
Beispiel #10
0
def init_deals_with_logging_speedy(trade_pairs, difference, file_name,
                                   processor, msg_queue):

    # FIXME move after deal placement ?

    global overall_profit_so_far
    overall_profit_so_far += trade_pairs.current_profit

    base_currency_id, dst_currency_id = split_currency_pairs(
        trade_pairs.deal_1.pair_id)

    msg = """We try to send following deals to exchange.
        <b>Expected profit in {base_coin}:</b> <i>{cur}</i>.
        <b>Overall:</b> <i>{tot}</i>
        <b>Difference in percents:</b> <i>{diff}</i>

                Deal details:
        {deal}
        """.format(base_coin=get_currency_name_by_id(base_currency_id),
                   cur=float_to_str(trade_pairs.current_profit),
                   tot=float_to_str(overall_profit_so_far),
                   diff=difference,
                   deal=str(trade_pairs))

    msg_queue.add_message(DEAL_INFO_MSG, msg)
    log_to_file(msg, file_name)

    if not YES_I_KNOW_WHAT_AM_I_DOING:
        die_hard("init_deals_with_logging_speedy called for {f}".format(
            f=trade_pairs))

    parallel_deals = []

    for order in [trade_pairs.deal_1, trade_pairs.deal_2]:
        method_for_url = dao.get_method_for_create_url_trade_by_exchange_id(
            order)
        # key, pair_name, price, amount
        key = get_key_by_exchange(order.exchange_id)
        pair_name = get_currency_pair_name_by_exchange_id(
            order.pair_id, order.exchange_id)
        post_details = method_for_url(key, pair_name, order.price,
                                      order.volume)
        constructor = return_with_no_change

        wu = WorkUnit(post_details.final_url, constructor, order)
        wu.add_post_details(post_details)

        parallel_deals.append(wu)

    res = processor.process_async_post(parallel_deals, DEAL_MAX_TIMEOUT)

    if res is None:
        log_to_file(
            "For TradePair - {tp} result is {res}".format(tp=trade_pairs,
                                                          res=res), file_name)
        log_to_file(
            "For TradePair - {tp} result is {res}".format(tp=trade_pairs,
                                                          res=res),
            ERROR_LOG_FILE_NAME)
        return

    # check for errors only
    for entry in res:
        json_response, order = entry
        if "ERROR" in json_response:

            msg = """   <b>ERROR: </b>NONE
            During deal placement: {u1}
            Details: {err_msg}
            """.format(u1=order, err_msg=json_response)

            msg_queue.add_order(FAILED_ORDERS_MSG, order)

        else:
            msg = """ For trade {trade}
            Response is {resp} """.format(trade=order, resp=json_response)

        print_to_console(msg, LOG_ALL_ERRORS)
        msg_queue.add_message(DEBUG_INFO_MSG, msg)
        log_to_file(msg, file_name)

    for order in [trade_pairs.deal_1, trade_pairs.deal_2]:
        msg_queue.add_order(ORDERS_MSG, order)
Beispiel #11
0
    orders, history_trades = prepare_data(pg_conn, start_time, end_time)

    missing_orders, failed_orders, orders_with_trades = group_trades_by_orders(
        orders, history_trades)

    # 2 stage - bucketing all that crap by pair_id
    trades_to_order = defaultdict(list)
    for order, trade_list in orders_with_trades:
        trades_to_order[order.pair_id].append((order, trade_list))

    total_profit_by_base = Counter()
    profit_details = defaultdict(list)

    for pair_id in trades_to_order:
        profit_pair, profit_base = compute_profit_by_pair(
            pair_id, trades_to_order[pair_id])
        base_currency_id, dst_currency_id = split_currency_pairs(pair_id)

        total_profit_by_base[base_currency_id] += profit_base

        profit_details[base_currency_id].append(
            ProfitDetails(base_currency_id, dst_currency_id, pair_id,
                          profit_pair, profit_base))

    loss_details, total_loss_by_base = compute_loss(orders_with_trades)

    save_report(start_time, end_time, total_profit_by_base, profit_details,
                missing_orders, failed_orders, loss_details,
                total_loss_by_base, orders, history_trades)