Пример #1
0
def withdraw(exchange_name, target_exchange_name, amount_str):
    db = session.get_a_trading_db_mysql_session()
    try:
        exchange_data = make_exchange_data_from_key(exchange_name, db)
        target_exchange_data = make_exchange_data_from_key(target_exchange_name, db)
        target_exchange = make_exchange_from_key(target_exchange_name)
        amount = Money.loads(amount_str)
        
        addr = target_exchange.current_deposit_address
        exchange_data.record_withdrawal(target_exchange_data, amount, addr)
        session.commit_mysql_session(db)
        logger.info(tc.colored("Recorded %s withdrawal from %s" % (amount, exchange_name), "green"))
    finally:
        db.remove()
Пример #2
0
def get_burn_transactions(db, start_time, end_time):
    """
    Get the list of transactions associated with the 'BURN' account in the databse. If
    there is no burn account, this function will return None.
    """
    burn_exchange_data = None

    try:
        burn_exchange_data = exchange_factory.make_exchange_data_from_key(
            'BURN', db)
    except Exception as e:
        logger.info(NO_BURN_ACCOUNT_WARNING)

        return None

    burn_exchange_id = burn_exchange_data.exchange_id

    burn_transactions = db.query(Transaction)\
        .filter(Transaction.transaction_status == Transaction.COMPLETED)\
        .filter(Transaction.time_completed >= start_time)\
        .filter(Transaction.time_completed < end_time)\
        .filter(Transaction.exchange_id == burn_exchange_id)\
        .order_by(Transaction.time_completed.desc())\
        .all()

    return burn_transactions
Пример #3
0
def withdraw_fiat(exchange_name, target_exchange_name, amount_str, deposit_amount_str, transaction_details):
    db = session.get_a_trading_db_mysql_session()
    try:
        exchange_data = make_exchange_data_from_key(exchange_name, db)
        target_exchange_data = make_exchange_data_from_key(target_exchange_name, db)
        amount = Money.loads(amount_str)
        if deposit_amount_str:
            deposit_amount = Money.loads(deposit_amount_str)
            exchange_data.record_fiat_withdrawal(target_exchange_data, amount, deposit_amount=deposit_amount, transaction_details=transaction_details)
        else:
            exchange_data.record_fiat_withdrawal(target_exchange_data, amount, transaction_details=transaction_details)
            
        session.commit_mysql_session(db)
        logger.info(tc.colored("Recorded %s withdrawal from %s" % (amount, exchange_name), "green"))
    finally:
        db.remove()
Пример #4
0
def audit_bank_accounts(db, scraper):
    """
    Check the balances of each bank account. If they differ, look for and add the new transactions.

    Writes BANK_AUDIT_<key> heartbeats on success.
    """
    try:
        account_data = scraper.load()
    except Scraper.MaintenanceException as e:
        # The heartbeats will fail, but the audit will retry every hour.
        scraper_name = scraper.__class__.__name__
        logger.info(
            tc.colored('%s: Service Unavailable' % scraper_name, 'yellow'))

        msg = str(e)
        if msg:
            logger.info(tc.colored(msg, 'yellow'))

        return

    for account in account_data:
        account_num = account['account_number']
        account_key = account_num_to_key(account_num)

        db_account = exchange_factory.make_exchange_data_from_key(
            account_key, db)

        db_balance = db_account.balance.fiat()
        ledger_balance = db_account.ledger_balance().fiat()

        if ledger_balance != db_balance:
            msg = 'DB balance: %s != Ledger balance: %s' % (db_balance,
                                                            ledger_balance)
            logger.info(tc.colored(msg, 'red'))
            return

        bank_balance = account['balance']

        if bank_balance == db_balance:
            success(account_key)
        else:
            balance_diff = bank_balance - db_balance
            transactions = scraper.load_transactions(account_num)

            new_transactions = find_new_transactions(transactions,
                                                     balance_diff)
            record_transactions(db_account, new_transactions, db)

            db_balance = db_account.balance.fiat()
            if bank_balance == db_balance:
                success(account_key)
            else:
                msg = 'Our balance: %s != Bank balance: %s' % (db_balance,
                                                               bank_balance)
                logger.info(tc.colored(msg, 'red'))
Пример #5
0
def manual_btc_withdrawals(db):
    """
    Check the Manual BTC exchanges for being above their target. Ping a dev on hipchat if they are.
    """

    logger.info('Running manual BTC withdrawals')

    for name, target in MANUAL_BTC_EXCHANGES.iteritems():
        exchange_db = exchange_factory.make_exchange_data_from_key(name, db)
        if exchange_db.balance['BTC'] > target:
            withdrawal_amount = exchange_db.balance['BTC'] - target
            if withdrawal_amount > BTC_TRANSFER_UNIT:
                btc_withdrawal_notification(exchange_db, withdrawal_amount)
Пример #6
0
def transaction_complete(exchange_name, currency):
    db = session.get_a_trading_db_mysql_session()
    try:
        exchange_data = make_exchange_data_from_key(exchange_name, db)
        tr = db.query(Transaction).filter_by(exchange=exchange_data).filter_by(_amount_currency=currency).filter_by(transaction_status=Transaction.IN_TRANSIT).order_by(Transaction.time_created).first()
        if tr:
            tr.complete()
            session.commit_mysql_session(db)
            if tr.transaction_type == Transaction.DEPOSIT:
                action = "deposit to"
            elif tr.transaction_type == Transaction.WITHDRAWL:
                action = "withdrawal from"
            logger.info(tc.colored("Recorded %s %s %s" % (tr.amount, action, exchange_name), "green"))
        else:
            logger.info(tc.colored("No Transaction of that currency found", "red"))
    finally:
        db.remove()
Пример #7
0
def record_reverse_burn(db_account, transaction, db):
    """
    Record transactions which "unexpectedly" put money back into our bank account.

    We expect this for interest, Matinee payments, reversed bank errors, etc.
    """
    if transaction['type'] != Transaction.DEPOSIT:
        raise ValueError('Reverse burn must be a deposit')

    amount = transaction['amount']

    transaction_details = {}
    transaction_details['description'] = transaction['description']

    burn_account = exchange_factory.make_exchange_data_from_key('BURN', db)

    deposit, __ = burn_account.record_fiat_withdrawal(
        db_account,
        amount,
        transaction_details=transaction_details,
    )
    deposit.complete()
Пример #8
0
def record_burn(db_account, transaction, db):
    """
    Record transactions which "unexpectedly" took money out of our bank account.

    We expect this for burn: payroll, rent, bills, etc.
    """
    if transaction['type'] != Transaction.WITHDRAWL:
        raise ValueError('Burn must be a withdrawal')

    amount = transaction['amount']

    transaction_details = {}
    transaction_details['description'] = transaction['description']

    burn_account = exchange_factory.make_exchange_data_from_key('BURN', db)

    deposit, __ = db_account.record_fiat_withdrawal(
        burn_account,
        amount,
        transaction_details=transaction_details,
    )
    deposit.complete()
Пример #9
0
    def get_trading_bank_accounts(self):
        trading_bank_acount_keys = ['BMO_USD', 'BMO_CAD']

        bank_account_infos = []

        for key in trading_bank_acount_keys:
            account = exchange_factory.make_exchange_data_from_key(
                key,
                self.trading_db,
            )

            account_info = {
                'name':
                account.name,
                'balance':
                account.balance.fiat(),
                'highlight':
                account.balance.fiat() > BANK_ACCOUNT_HIGHLIGHT_THRESHOLD,
            }
            bank_account_infos.append(account_info)

        return bank_account_infos
Пример #10
0
def ledger_balance(db,
                   start_time=None,
                   end_time=None,
                   include_pending=False,
                   exchange_names=[]):
    """
    Returns the exchange's balance as calculated from its ledger of trades and
    transactions.

    With no params specified we return the current balance.
    With end_time specified we return the balance at a historical point.
    With start_time specified we return a balance diff which can be useful for
    performance (if you know the balance on one day, you can get the next day's balance
    by only looking at that next days ledgers instead of from the beginning).
    """

    if start_time and start_time < EARLIEST_CORRECT_LEDGER_DATE:
        raise ValueError(
            'start_time must be later than %s' %
            EARLIEST_CORRECT_LEDGER_DATE, )

    if end_time and end_time < EARLIEST_CORRECT_LEDGER_DATE:
        raise ValueError(
            'end_time must be later than %s' % EARLIEST_CORRECT_LEDGER_DATE, )

    exchange_ids = []

    for exchange_name in exchange_names:
        exchange_data = exchange_factory.make_exchange_data_from_key(
            exchange_name, db)
        exchange_id = exchange_data.exchange_id
        exchange_ids.append(exchange_id)

    # Trades
    bid_prices = trade_position_query(
        db,
        Trade._price,
        Trade._price_currency,
        Trade.BID,
        start_time=start_time,
        end_time=end_time,
        exchange_names=exchange_names,
    )

    bid_volumes = trade_position_query(
        db,
        Trade._volume,
        Trade._volume_currency,
        Trade.BID,
        start_time=start_time,
        end_time=end_time,
        exchange_names=exchange_names,
    )

    ask_prices = trade_position_query(
        db,
        Trade._price,
        Trade._price_currency,
        Trade.ASK,
        start_time=start_time,
        end_time=end_time,
        exchange_names=exchange_names,
    )

    ask_volumes = trade_position_query(
        db,
        Trade._volume,
        Trade._volume_currency,
        Trade.ASK,
        start_time=start_time,
        end_time=end_time,
        exchange_names=exchange_names,
    )

    trade_fees = trade_position_query(
        db,
        Trade._fee,
        Trade._fee_currency,
        start_time=start_time,
        end_time=end_time,
        exchange_names=exchange_names,
    )

    # Transactions
    deposits = transaction_position_query(
        db,
        Transaction._amount,
        Transaction._amount_currency,
        transaction_type=Transaction.DEPOSIT,
        start_time=start_time,
        end_time=end_time,
        include_pending=include_pending,
        exchange_ids=exchange_ids,
    )

    withdrawals = transaction_position_query(
        db,
        Transaction._amount,
        Transaction._amount_currency,
        transaction_type=Transaction.WITHDRAWL,
        start_time=start_time,
        end_time=end_time,
        include_pending=include_pending,
        exchange_ids=exchange_ids,
    )

    transaction_fees = transaction_position_query(
        db,
        Transaction._fee,
        Transaction._fee_currency,
        start_time=start_time,
        end_time=end_time,
        include_pending=include_pending,
        exchange_ids=exchange_ids,
    )

    logger.debug('Bid Prices: %s' % bid_prices)
    logger.debug('Bid Volumes: %s' % bid_volumes)
    logger.debug('Ask Prices: %s' % ask_prices)
    logger.debug('Ask Volumes: %s' % ask_volumes)
    logger.debug('Trade Fees: %s' % trade_fees)

    logger.debug('Deposits: %s' % deposits)
    logger.debug('Withdrawals: %s' % withdrawals)
    logger.debug('Transaction Fees: %s' % transaction_fees)

    positive_position = sum([
        bid_volumes,
        ask_prices,
        deposits,
    ], Position())

    negative_position = sum([
        bid_prices,
        ask_volumes,
        trade_fees,
        withdrawals,
        transaction_fees,
    ], Position())

    total_position = positive_position - negative_position
    return total_position
Пример #11
0
    def get_ledger_table_for_time(self,
                                  exchange_name,
                                  start_time,
                                  end_time,
                                  currency=None):
        if currency:
            currency = currency.upper()

        exchange_name = exchange_name.capitalize()
        exchange = exchange_factory.make_exchange_from_key(exchange_name)
        exchange_data = exchange_factory.make_exchange_data_from_key(
            exchange_name,
            self.trading_db,
        )

        if exchange:
            # Normal bitcoin exchange.
            fiat_currency = exchange.currency
        else:
            # Bank Accounts don't have exchange objects.
            fiat_currency = self.currency_for_bank_account(exchange_name)

            # Bank Accounts only have one currency, so we set a currency filter by
            # default. It just makes the UI look nicer instead of having an empty BTC
            # column.
            currency = fiat_currency

        ledger = exchange_data.ledger(
            start_time=start_time,
            end_time=end_time,
            currency=currency,
        )

        # ledger is empty for this time period.
        if len(ledger) == 0:
            return fiat_currency, currency, []

        # get the exchange balance from before these ledger entries started
        oldest_entry = ledger[-1]
        oldest_time = oldest_entry.time_created

        # There can be multiple entries at the same time
        entries_at_oldest_time = []

        for entry in ledger:
            if isinstance(entry, Trade) and entry.time_created == oldest_time:
                entries_at_oldest_time.append(entry)
            elif isinstance(
                    entry,
                    Transaction) and entry.time_completed == oldest_time:
                entries_at_oldest_time.append(entry)

        oldest_time = pytz.utc.localize(oldest_time)
        balance_at_oldest_time = exchange_data.ledger_balance(
            end_time=oldest_time)

        # balance_at_oldest_time includes all the entries_at_oldest_time
        # so we need to remove them to get the pre-ledger balance
        pre_ledger_balance = balance_at_oldest_time

        for entry in entries_at_oldest_time:
            pre_ledger_balance -= entry.position

        starting_ledger_balance = exchange_data.ledger_balance(
            end_time=start_time)

        ledger_table = []

        for entry in ledger:
            if isinstance(entry, Trade):
                table_entries = self.table_entries_from_trade(entry)
            elif isinstance(entry, Transaction):
                table_entries = self.table_entries_from_transaction(entry)

            ledger_table += table_entries

        ledger_table = self.filter_to_currency(ledger_table, currency)

        current_balance = starting_ledger_balance

        for table_entry in reversed(ledger_table):
            if 'credit' in table_entry:
                current_balance += table_entry['credit']
            if 'debit' in table_entry:
                current_balance -= table_entry['debit']

            table_entry['balance'] = current_balance

        return fiat_currency, currency, ledger_table
Пример #12
0
def get_ledger_table_for_time(exchange_name,
                              start_time,
                              end_time,
                              currency=None):
    if currency:
        currency = currency.upper()

    exchange_name = exchange_name.capitalize()
    exchange = exchange_factory.make_exchange_from_key(exchange_name)

    exchange_data = exchange_factory.make_exchange_data_from_key(
        exchange_name,
        db,
    )

    fiat_currency = exchange.currency

    ledger = exchange_data.ledger(
        start_time=start_time,
        end_time=end_time,
        currency=currency,
    )

    # ledger is empty for this time period.
    if len(ledger) == 0:
        return fiat_currency, currency, []

    # get the exchange balance from before these ledger entries started
    oldest_entry = ledger[-1]
    oldest_time = oldest_entry.time_created

    # There can be multiple entries at the same time
    entries_at_oldest_time = []

    for entry in ledger:
        if isinstance(entry, Trade) and entry.time_created == oldest_time:
            entries_at_oldest_time.append(entry)
        elif isinstance(entry,
                        Transaction) and entry.time_completed == oldest_time:
            entries_at_oldest_time.append(entry)

    oldest_time = pytz.utc.localize(oldest_time)
    balance_at_oldest_time = exchange_data.ledger_balance(end_time=oldest_time)

    # balance_at_oldest_time includes all the entries_at_oldest_time
    # so we need to remove them to get the pre-ledger balance
    pre_ledger_balance = balance_at_oldest_time

    for entry in entries_at_oldest_time:
        pre_ledger_balance -= entry.position

    starting_ledger_balance = exchange_data.ledger_balance(end_time=start_time)
    ledger_diff = exchange_data.ledger_balance(
        start_time=start_time,
        end_time=end_time,
    )
    ending_ledger_balance = starting_ledger_balance + ledger_diff

    ledger_table = []

    for entry in ledger:
        if isinstance(entry, Trade):
            table_entries = table_entries_from_trade(entry)
        elif isinstance(entry, Transaction):
            table_entries = table_entries_from_transaction(entry)

        ledger_table += table_entries

    #ledger_table = self.filter_to_currency(ledger_table, currency)

    current_balance = starting_ledger_balance

    for table_entry in reversed(ledger_table):
        if 'credit' in table_entry:
            current_balance += table_entry['credit']
        if 'debit' in table_entry:
            current_balance -= table_entry['debit']

        table_entry['balance'] = current_balance

    return fiat_currency, currency, ledger_table