Exemplo n.º 1
0
class Coinbase:
    def __init__(self, config):
        # TODO command-line parameters?
        # https://docs.python.org/3/library/argparse.html
        account = input("Account: ")
        if account == "Kevin" or "kevin" or "k":
            api_key = config["coinbase_api_kevin"]["key"]
            api_secret = config["coinbase_api_kevin"]["secret"]
        elif account == "Liang" or "liang" or "l":
            api_key = config["coinbase_api_liang"]["key"]
            api_secret = config["coinbase_api_liang"]["secret"]
        else:
            print("Account not found. Please add API keys to config.json")
            exit(1)
        self.client = Client(api_key, api_secret)

        # Initialize all calculated numbers
        self.accumulated_profit_btc = 0
        self.accumulated_profit_eth = 0
        self.total_btc_paid_fees = 0
        self.total_eth_paid_fees = 0
        self.total_btc_received = 0
        self.total_eth_received = 0

    def set_eth_price(self, price):
        self.current_eth_price = price
        # TODO automatically update ETH price

    def get_exchange_rate(self, coin="BTC", currency="USD"):
        """ Get BTC - USD exchange rate
            Bug for ETH-USD:
            https://community.coinbase.com/t/python-3-5-get-spot-price-for-eth-eur-returns-btc-usd/14273/9
            Modify source library code:
            https://stackoverflow.com/a/23075617/3751589
        """
        param = "{}-{}".format(coin, currency)
        return self.client.get_spot_price(currency_pair=param)

    def calculate_profit_loss(self):
        self.current_btc_price = float(
            self.get_exchange_rate("BTC", "USD").amount)
        # self.current_eth_price = float(self.get_exchange_rate("ETH", "USD").amount)

        # Ask user for balance outside of Coinbase
        BTC_external_balance = float(input('BTC external balance: '))
        ETH_external_balance = float(input('ETH external balance: '))

        # # Print transactions?
        # print_transactions = input("Print transactions? ")
        # if print_transactions == "Y" or "y" or "yes" or "Yes" or "si" or "si patron":
        #         # do everything inside for then print the following
        #         print("\tBuy transaction: -{}".format(amount_paid_fees))
        #         print("\t{} transaction: {}".format(transaction.type.title(), amount_received))
        # elif print_transactions == "N" or "n" or "no" or "No" or "fk off boi":
        #         # do everything inside for loop
        # else:
        #     print("Answer the question dumbass. Yes or No")

        # Get all accounts listing
        accounts = self._get_accounts()
        print("Accounts retrieved: {}\n".format(len(accounts.data)))

        # Read each account
        for account in accounts.data:
            currency = account.balance.currency
            if currency in (
                    "USD", "LTC"
            ) or account.name == "My Vault":  # Ignore these accounts
                # TODO add USD wallet
                continue
            print(currency)

            print("Calculating currency: {}".format(currency))
            print("{}: {} {}".format(account.name, account.balance.amount,
                                     currency))

            # Get all transactions
            transactions = account.get_transactions(
                start_after="1805ae5b-f65b-5825-b780-9c6cecdec1cf", limit=100)
            """ Documentation for argument syntax in get_transactions
                https://github.com/coinbase/coinbase-python/blob/f9ed2249865c2012e3b86106dad5f8c6068366ed/coinbase/wallet/model.py#L168
            """
            # TODO regex or some way to find everyones start_after
            # https://stackoverflow.com/questions/44351034/pagination-on-coinbase-python-api
            for transaction in transactions.data:
                if transaction.status != "completed":
                    print("\tIncomplete transaction...")
                    continue

            # Calculate for each transaction type
            # Calculate all BUYS
                if transaction.type == "buy":
                    transaction_id = transaction.buy.id
                    transaction_detail = self._get_buy_transaction(
                        account.id, transaction_id)

                    # Calculate price point during purchase
                    amount_paid = float(transaction_detail.subtotal.amount
                                        )  # USD paid before fees
                    coins_bought = float(
                        transaction_detail.amount.amount
                    )  # Total coins received from purchase
                    purchase_price = amount_paid / coins_bought  # Price of BTC/ETH at time of buying
                    amount_paid_fees = float(
                        transaction.native_amount.amount
                    )  # USD paid after fees (total paid)

                    # Calculate profit-loss
                    if currency == "BTC":
                        self.accumulated_profit_btc -= amount_paid_fees
                        self.total_btc_paid_fees += amount_paid_fees
                        #TODO prompt user if they want to print all transactions
                        #print("\tBuy transaction: -{}".format(amount_paid_fees))
                    elif currency == "ETH":
                        self.accumulated_profit_eth -= amount_paid_fees
                        self.total_eth_paid_fees += amount_paid_fees
                        #TODO prompt user if they want to print all transactions
                        #print("\tBuy transaction: -{}".format(amount_paid_fees)

                # Calculate all SELLS
                elif transaction.type in ("sell"):
                    # Amount received after fees
                    amount_received = float(transaction.native_amount.amount)
                    amount_received = amount_received * -1

                    # Accumulate profit-loss
                    if currency == "BTC":
                        self.accumulated_profit_btc += amount_received
                        self.total_btc_received += amount_received
                    elif currency == "ETH":
                        self.accumulated_profit_eth += amount_received
                        self.total_eth_received += amount_received

                    #TODO prompt user if they want to print all transactions
                    #print("\t{} transaction: {}".format(transaction.type.title(), amount_received))

            # Add current Coinbase balance + current external balance to profit/Loss
            if currency == "BTC":
                # BTC_external_value = BTC_external_balance * self.btc_current_price
                account.balance.amount = float(account.balance.amount)
                self.accumulated_profit_btc += (
                    BTC_external_balance +
                    account.balance.amount) * self.current_btc_price
                self.percent_profit_btc = self.accumulated_profit_btc / self.total_btc_paid_fees
                self.total_btc_balance = (
                    BTC_external_balance +
                    account.balance.amount) * self.current_btc_price
            elif currency == "ETH":
                # ETH_external_value = ETH_external_balance * self.eth_current_price
                account.balance.amount = float(account.balance.amount)
                self.accumulated_profit_eth += (
                    ETH_external_balance +
                    account.balance.amount) * self.current_eth_price
                self.percent_profit_eth = self.accumulated_profit_eth / self.total_eth_paid_fees
                self.total_eth_balance = (
                    ETH_external_balance +
                    account.balance.amount) * self.current_eth_price
            # Print accumulated profit/loss
            if currency == "BTC":
                print("\nProfit/Loss ({}): ${:.2f} or {:.2f}%".format(
                    currency, self.accumulated_profit_btc,
                    (self.percent_profit_btc * 100)))
            elif currency == "ETH":
                print("\nProfit/Loss ({}): ${:.2f} or {:.2f}%\n".format(
                    currency, self.accumulated_profit_eth,
                    (self.percent_profit_eth * 100)))

        # Print balance start --> balance now
        self.total_accumulated_profit = self.accumulated_profit_btc + self.accumulated_profit_eth
        self.total_paid_fees = self.total_btc_paid_fees + self.total_eth_paid_fees
        self.total_acc_balance = self.total_btc_balance + self.total_eth_balance + self.total_eth_received + self.total_btc_received
        print("\nTotal USD Value (ALL): ${:.2f} --> ${:.2f}".format(
            self.total_paid_fees, self.total_acc_balance))

        # Print total account (BTC + ETH) profit/loss
        self.percent_profit_total = (
            self.accumulated_profit_btc + self.accumulated_profit_eth) / (
                self.total_eth_paid_fees + self.total_btc_paid_fees) * 100
        print("Profit/Loss (ALL): ${:.2f} or {:.2f}%\n".format(
            self.accumulated_profit_btc + self.accumulated_profit_eth,
            self.percent_profit_total))

    def _get_accounts(self):
        return self.client.get_accounts()

    def _get_buy_transaction(self, account_id, transaction_id):
        return self.client.get_buy(account_id, transaction_id)
Exemplo n.º 2
0
 def test_get_buy(self):
     client = Client(api_key, api_secret)
     buy = client.get_buy('foo', 'bar')
     self.assertIsInstance(buy, Buy)
     self.assertEqual(buy, mock_item)
Exemplo n.º 3
0
class CoinbaseInterface(PlatformInterface):
    """
    Class implementing all the methods allowing to calculate the differents
    overall values of accounts at given times. It allows also to enumerate
    all the transactions that can be impacted by taxes
    """

    def __init__(self, api_key: str, api_secret: str, price_finder: List[PriceFinder]) -> None:
        # Call the upper class initialization
        super().__init__(price_finder)

        # Create the Coinbase authenticated client that we will use
        self.api_client = Client(api_key, api_secret)

        # Load all accounts and transactions
        fcrypt_log.info("[COINBASE][INITIALIZATION] Loading all accounts...")
        self._load_all_accounts()
        fcrypt_log.info("[COINBASE][INITIALIZATION] Loading all transactions...")
        self._load_all_transactions()

    @staticmethod
    def _extract_account_id(path: str) -> str:
        """
        Function allowing to extract an account UUID from a "resource_path" given
        for each transaction done on Coinbase.
        :param path: "resource_path" to extract the account id from
        :type path: str
        :returns: str -- The account id
        """
        items = path.split("/")

        # Check that the path look like we want
        if items[2] != "accounts":
            raise ValueError("It looks like the resource path is not like we want...")

        # Return the account id
        return items[3]

    def _load_all_accounts(self):
        """
        This function allows to load every account that the user has on Coinbase
        These accounts will be used to calculate the taxes, 'in fine'.
        Only the accounts with an real UUID are taken into account
        """
        accounts_list = []
        other_pages = True
        last_id = ""
        while other_pages:
            # Get account according to pagination
            if last_id == "":
                api_answer = self.api_client.get_accounts()
            else:
                api_answer = self.api_client.get_accounts(starting_after=last_id)

            accounts_list = accounts_list + api_answer['data']
            if ((api_answer.pagination is not None) and (api_answer.pagination["next_uri"] is not None) and
                    (api_answer.pagination["next_uri"] != "")):
                # Get the pagination object
                pagination_obj = api_answer.pagination
                # Extract 'starting_after' key from next_uri
                parsed = urlparse.urlparse(pagination_obj["next_uri"])
                last_id = parse_qs(parsed.query)['starting_after'][0]
            else:
                other_pages = False

        # Save all used accounts
        for account in accounts_list:

            # If the ID is a valid UUID, save the account and print it in DEBUG logs
            match = re.search(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", account['id'])
            if match:
                # Get the various values
                id = account['id']
                name = account['name']
                crypto_balance = account['balance']['amount']
                crypto_currency = account['currency']
                native_balance = account['native_balance']['amount']
                native_currency = account['native_balance']['currency']

                # Debug print
                fcrypt_log.debug(
                    f"Adding account: {id} ==> {name}: {crypto_balance} {crypto_currency}" +
                    f" ({native_balance} {native_currency})")

                # Add the account in our list
                self.accounts.append(account)

    def _load_all_transactions(self):
        """
        This function allows to load every transaction that the user has done on Coinbase
        These transactions, in fine, will allow us to go back in time in the account, to know
        what was on each account, at a given time
        """
        # Get all transactions
        for account in self.accounts:
            transactions_list = []
            other_pages = True
            last_id = ""

            while other_pages:
                # Get account according to pagination
                if last_id == "":
                    # Get the transactions for this account
                    tmp_transactions = self.api_client.get_transactions(account['id'])
                else:
                    # Get the transactions for this account
                    tmp_transactions = self.api_client.get_transactions(account['id'], starting_after=last_id)

                transactions_list = transactions_list + tmp_transactions['data']
                if ((tmp_transactions.pagination is not None) and
                    (tmp_transactions.pagination["next_uri"] is not None) and
                        (tmp_transactions.pagination["next_uri"] != "")):
                    # Get the pagination object
                    pagination_obj = tmp_transactions.pagination
                    # Extract 'starting_after' key from next_uri
                    parsed = urlparse.urlparse(pagination_obj["next_uri"])
                    last_id = parse_qs(parsed.query)['starting_after'][0]
                else:
                    other_pages = False

            # Print the transactions
            for transaction in transactions_list:
                # print(transaction)
                transaction_type = transaction['type']
                amount = transaction['amount']['amount']
                currency = transaction['amount']['currency']
                date = transaction['updated_at']
                if not str.startswith(amount, "-"):
                    amount = "+" + amount
                account = self._extract_account_id(transaction['resource_path'])
                fcrypt_log.debug(f"[TRANSACTION][{transaction_type}] {date}: {amount} {currency} ==> {account}")

            self.transactions.extend(transactions_list)

    def get_wallet_balance_at(self, currency: str, time: datetime.datetime) -> Decimal:
        """
        This function allows to get the balance of a wallet at a given time.

        :param currency: Currency we want the value for
        :type currency: str
        :param time: Time where the value is wanted
        :type time: datetime.datetime
        :returns: Decimal -- The wallet balance at the given time
        """
        # Firstly, get the corresponding account ID
        account_id = ""
        for account in self.accounts:
            if ('currency' in account) and (account['currency'] == currency):
                account_id = account['id']
                current_balance = Decimal(account['balance']['amount'])

        if account_id == "":
            raise ValueError("No account found for this currency")

        # Then apply every transaction in reverse if the datetime of this transaction
        # is posterior to the wanted datetime
        for transaction in self.transactions:
            # Extract account ID
            tmp_account_id = self._extract_account_id(transaction['resource_path'])
            # Check if the account ids correspond
            if (tmp_account_id == account_id) and transaction['status'] == 'completed':
                # Extract the datetime
                operation_datetime = isoparse(transaction['updated_at'])
                # If datetime posterior or equal to the time given by user, reverse it
                if operation_datetime >= time:
                    trans_amount = Decimal(transaction['amount']['amount'])
                    tmp_balance = current_balance - trans_amount
                    fcrypt_log.debug(f"[REVERSED TRANSACTION] {trans_amount} {currency} ==> {account_id}")
                    fcrypt_log.debug(
                        f"[REVERSED TRANSACTION] Operation {current_balance}-{trans_amount} = {tmp_balance}")
                    current_balance = tmp_balance

        return current_balance

    def get_wallet_value_at(self, crypto_currency: str, fiat_currency: str, time: datetime.datetime) -> Decimal:
        """
        This function allows to get the value of a wallet at a given time.

        :param crypto_currency: Crypto currency of the wallet
        :type crypto_currency: str
        :param fiat_currency: Fiat currency for the result (EUR, USD, etc.)
        :type fiat_currency: str
        :param time: Time where the value is wanted
        :type time: datetime.datetime
        :returns: Decimal -- The wallet value at the given time
        """
        # Firstly, get the wallet balance at the given time
        balance = self.get_wallet_balance_at(crypto_currency, time)

        time_str = str(time)
        normal_balance = str(balance.normalize())

        # Print debug
        fcrypt_log.debug(f"[WALLET] Balance at {time_str}: {normal_balance} {crypto_currency}")

        if balance != 0:

            # Now get the equivalent value in fiat
            rate_currency = crypto_currency + "-" + fiat_currency
            rate_value = self._find_rate_value_from_finders(rate_currency, time)

            if rate_value == Decimal(0):
                # Print error
                fcrypt_log.warning(
                    f"[WALLET] NO RATE FOUND FOR NOT NULL BALANCE !!! Currency: {crypto_currency} \
 - Fiat: {fiat_currency}")
                # Return 0
                wallet_value = Decimal(0)
            else:
                # Calculate the wallet value
                wallet_value = rate_value * balance

                # Print info
                fcrypt_log.debug(
                    f"[WALLET] Value of {crypto_currency} wallet at {time_str}: {wallet_value} {fiat_currency}")

        else:
            wallet_value = Decimal(0)

        return wallet_value

    def get_all_wallets_value(self, currency: str, time: datetime.datetime) -> Decimal:
        """
        This function allows to get the value of all the crypto-wallets of
        a user at a given time

        :param currency: Fiat currency we want for the value (ISO 4217)
        :type currency: str
        :param time: Time where the value is wanted
        :type time: datetime.datetime
        :returns: Decimal -- The overall value at the given time
        """
        # Initialize overall value of the wallet
        overall_value = Decimal(0)

        # For each crypto account (except fiat currency), calculate the wallet value
        for account in self.accounts:
            if account['currency'] != currency:
                wallet_value = self.get_wallet_value_at(account['currency'], currency, time)
                # Add the wallet value to the overall value
                overall_value += wallet_value

        return overall_value

    def all_sell_transactions_generator(self, currency: str, end_time: datetime.datetime) -> Generator:
        """
        This function returns a generator that can be used in a for loop to get
        every "sell" transactions done between "start_time" and "end_time"

        :param currency: Fiat currency we want for the value (ISO 4217)
        :type currency: str
        :param start_time: Begin of the tax period
        :type start_time: datetime.datetime
        :param end_time: End of the tax period
        :type end_time: datetime.datetime
        :returns: Generator -- Generator to get each transaction object \
        """
        # Get the correct ID for this currency in order to ignore it
        account_to_ignore_id = self._find_account_for_currency(currency)

        if account_to_ignore_id == "":
            raise ValueError(f"Account not found with the given currency: {currency}")

        # Now that we have the right account
        for transaction in self.transactions:
            # Extract the account ID from the resource path
            account = self._extract_account_id(transaction['resource_path'])

            # Check that this is the right account and that is a match
            if (account != account_to_ignore_id) and (transaction["type"] == "sell"):
                # Get the amount of the transaction
                amount = transaction["native_amount"]["amount"]
                local_currency = transaction["native_amount"]["currency"]

                if local_currency != currency:
                    error_msg = f"The local currency found \"{local_currency}\" does not match \
                                  the specified currency \"{currency}\"!"
                    raise ValueError(error_msg)

                # Check the time when this sell appeared
                transaction_time = isoparse(transaction['created_at'])

                if (transaction_time < end_time):
                    # This is something we want, find the corresponding fee

                    # Request the full sell transaction object
                    current_sell = self.api_client.get_sell(account, transaction["sell"]["id"])

                    # Get the fee amount from the full sell object
                    fee_amount = current_sell["fees"][0]["amount"]["amount"]

                    # Declare the dictionnary to return
                    tmp_dict = {
                        "date": transaction_time,
                        "currency": local_currency,
                        "amount": amount,
                        "fee": fee_amount
                    }

                    yield tmp_dict

    def all_buy_transactions_generator(self, currency: str, end_time: datetime.datetime) -> Generator:
        """
        This function returns a generator that can be used in a for loop to get
        every "buy" transactions done before "end_time"

        :param currency: Fiat currency we want for the value (ISO 4217)
        :type currency: str
        :param end_time: End of the tax period
        :type end_time: datetime.datetime
        :returns: Generator -- Generator to get each transaction object
        """
        # Get the correct ID for this currency in order to ignore it
        account_to_ignore_id = self._find_account_for_currency(currency)

        if account_to_ignore_id == "":
            raise ValueError(f"Account not found with the given currency: {currency}")

        # Now that we have the right account
        for transaction in self.transactions:
            # Extract the account ID from the resource path
            account = self._extract_account_id(transaction['resource_path'])

            # Check that this is the right account and that is a match
            if (account != account_to_ignore_id) and (transaction["type"] == "buy"):
                # Get the amount of the transaction
                amount = transaction["native_amount"]["amount"]
                local_currency = transaction["native_amount"]["currency"]

                if local_currency != currency:
                    error_msg = f"The local currency found \"{local_currency}\" does not match \
                                 the specified currency \"{currency}\"!"
                    raise ValueError(error_msg)

                # Check the time when this sell appeared
                transaction_time = isoparse(transaction['created_at'])

                if (transaction_time < end_time):
                    # This is something we want, find the corresponding fee

                    # Request the full sell transaction object
                    current_buy = self.api_client.get_buy(account, transaction["buy"]["id"])

                    # Get the fee amount from the full sell object
                    fee_amount = current_buy["fees"][0]["amount"]["amount"]

                    # Declare the dictionnary to return
                    tmp_dict = {
                        "date": transaction_time,
                        "currency": local_currency,
                        "amount": amount,
                        "fee": fee_amount
                    }

                    yield tmp_dict
Exemplo n.º 4
0
 def test_get_buy(self):
   client = Client(api_key, api_secret)
   buy = client.get_buy('foo', 'bar')
   self.assertIsInstance(buy, Buy)
   self.assertEqual(buy, mock_item)
Exemplo n.º 5
0
class Coinbase:
    def __init__(self, config, user, verbose):
        # TODO: Add JSON schema validation to main.py
        # TODO: Verify Coinbase SDK: UserWarning: Please supply API version (YYYY-MM-DD) as CB-VERSION header
        api_key = config[user]["coinbase_api"]["key"]
        api_secret = config[user]["coinbase_api"]["secret"]

        self.client = Client(api_key, api_secret)

        self.verbose = verbose

        # Initialize all calculated numbers
        self.accumulated_profit_btc = 0
        self.accumulated_profit_eth = 0
        self.total_btc_paid_fees = 0
        self.total_eth_paid_fees = 0
        self.total_btc_received = 0
        self.total_eth_received = 0

    def set_eth_price(self, price):
        """ TODO automatically update ETH price, Coinbase API error
        """
        self.current_eth_price = price

    def get_exchange_rate(self, coin="BTC", currency="USD"):
        """ Get BTC - USD exchange rate
            Bug for ETH-USD:
            https://community.coinbase.com/t/python-3-5-get-spot-price-for-eth-eur-returns-btc-usd/14273/9
            Modify source library code:
            https://stackoverflow.com/a/23075617/3751589
        """
        param = "{}-{}".format(coin, currency)
        return self.client.get_spot_price(currency_pair=param)

    def calculate_profit_loss(self):
        self.current_btc_price = float(
            self.get_exchange_rate("BTC", "USD").amount)
        # self.current_eth_price = float(self.get_exchange_rate("ETH", "USD").amount)

        # Ask user for balance outside of Coinbase
        BTC_external_balance = float(input('BTC external balance: '))
        ETH_external_balance = float(input('ETH external balance: '))

        # Get all accounts listing
        accounts = self._get_accounts()
        print("Accounts retrieved: {}\n".format(len(accounts.data)))

        # Read each account
        for account in accounts.data:
            currency = account.balance.currency
            # TODO add support for USD wallet
            if currency in ("USD", "LTC") or account.name == "My Vault":
                continue

            print("Calculating currency: {}".format(currency))
            print("{}: {} {}".format(account.name, account.balance.amount,
                                     currency))

            # Get all transactions
            transactions = account.get_transactions(limit=100)
            """ TODO regex or some way to find pagination start_after
                https://stackoverflow.com/questions/44351034/pagination-on-coinbase-python-api
                Coinbase SDK code for get_transactions
                https://github.com/coinbase/coinbase-python/blob/f9ed2249865c2012e3b86106dad5f8c6068366ed/coinbase/wallet/model.py#L168
            """
            for transaction in transactions.data:
                if transaction.status != "completed":
                    print("\tIncomplete transaction...")
                    continue

                # Calculate for each transaction type
                # Calculate all BUYS
                if transaction.type == "buy":
                    transaction_id = transaction.buy.id
                    transaction_detail = self._get_buy_transaction(
                        account.id, transaction_id)

                    # Calculate price point during purchase
                    amount_paid = float(transaction_detail.subtotal.amount
                                        )  # USD paid before fees
                    coins_bought = float(
                        transaction_detail.amount.amount
                    )  # Total coins received from purchase
                    purchase_price = amount_paid / coins_bought  # Price of BTC/ETH at time of buying
                    amount_paid_fees = float(
                        transaction.native_amount.amount
                    )  # USD paid after fees (total paid)

                    # TODO: Do this next -- turn into dictionary
                    # self.total_paid_fees = {}
                    # self.total_paid_fees[currency]

                    # Calculate profit-loss
                    if currency == "BTC":
                        self.accumulated_profit_btc -= amount_paid_fees
                        self.total_btc_paid_fees += amount_paid_fees
                    elif currency == "ETH":
                        self.accumulated_profit_eth -= amount_paid_fees
                        self.total_eth_paid_fees += amount_paid_fees

                    if (self.verbose):
                        print(
                            "\tBuy transaction: -{}".format(amount_paid_fees))

                # Calculate all SELLS
                elif transaction.type in ("sell"):
                    # Amount received after fees
                    amount_received = float(transaction.native_amount.amount)
                    amount_received = amount_received * -1

                    # Accumulate profit-loss
                    if currency == "BTC":
                        self.accumulated_profit_btc += amount_received
                        self.total_btc_received += amount_received
                    elif currency == "ETH":
                        self.accumulated_profit_eth += amount_received
                        self.total_eth_received += amount_received

                    if (self.verbose):
                        print("\t{} transaction: {}".format(
                            transaction.type.title(), amount_received))

            # Calculate total profit/loss
            # Add current Coinbase balance + current external balance to profit/loss
            if currency == "BTC":
                account.balance.amount = float(account.balance.amount)
                self.accumulated_profit_btc += (
                    BTC_external_balance +
                    account.balance.amount) * self.current_btc_price
                self.percent_profit_btc = self.accumulated_profit_btc / self.total_btc_paid_fees
                self.total_btc_balance = (
                    BTC_external_balance +
                    account.balance.amount) * self.current_btc_price
            elif currency == "ETH":
                account.balance.amount = float(account.balance.amount)
                self.accumulated_profit_eth += (
                    ETH_external_balance +
                    account.balance.amount) * self.current_eth_price
                self.percent_profit_eth = self.accumulated_profit_eth / self.total_eth_paid_fees
                self.total_eth_balance = (
                    ETH_external_balance +
                    account.balance.amount) * self.current_eth_price

            if currency == "BTC":
                print("\nProfit/Loss ({}): ${:.2f} or {:.2f}%".format(
                    currency, self.accumulated_profit_btc,
                    (self.percent_profit_btc * 100)))
            elif currency == "ETH":
                print("\nProfit/Loss ({}): ${:.2f} or {:.2f}%\n".format(
                    currency, self.accumulated_profit_eth,
                    (self.percent_profit_eth * 100)))

        # TODO: Fix this comment
        # TODO: `total_paid_fees` var name
        # TODO: Verify `total_paid_fees` value
        # Calculate how much you paid --> crypto assets in USD + profits you took out
        self.total_accumulated_profit = self.accumulated_profit_btc + self.accumulated_profit_eth
        self.total_paid_fees = self.total_btc_paid_fees + self.total_eth_paid_fees
        self.total_acc_balance = self.total_btc_balance + self.total_eth_balance + self.total_eth_received + self.total_btc_received
        print("\nTotal USD Value (ALL): ${:.2f} --> ${:.2f}".format(
            self.total_paid_fees, self.total_acc_balance))

        # Print total account (BTC + ETH) profit/loss
        self.percent_profit_total = (
            self.accumulated_profit_btc + self.accumulated_profit_eth) / (
                self.total_eth_paid_fees + self.total_btc_paid_fees) * 100
        print("Profit/Loss (ALL): ${:.2f} or {:.2f}%\n".format(
            self.accumulated_profit_btc + self.accumulated_profit_eth,
            self.percent_profit_total))

    def _get_accounts(self):
        return self.client.get_accounts()

    def _get_buy_transaction(self, account_id, transaction_id):
        return self.client.get_buy(account_id, transaction_id)