예제 #1
0
def import_transaction(
    account: models.Account,
    fiat_record: pd.Series,
    token_record: pd.Series,
) -> Tuple[models.Transaction, bool]:
    raw_record = _to_raw_record((fiat_record, token_record))
    executed_at = _parse_utc_datetime(fiat_record["UTC_Time"])
    symbol = token_record["Coin"]
    fiat_currency = fiat_record["Coin"]
    raw_fiat_value = to_decimal(fiat_record["Change"])
    fiat_value = raw_fiat_value
    from_currency = models.currency_enum_from_string(fiat_currency)

    if fiat_currency != models.Currency(account.currency).label:
        to_currency = account.currency
        exchange_rate = prices.get_closest_exchange_rate(
            executed_at.date(), from_currency, to_currency
        )
        if exchange_rate is None:
            raise CurrencyMismatch(
                "Couldn't convert the fiat to account currency, missing exchange rate"
            )
        else:
            fiat_value *= exchange_rate.value
            raw_record += f" exchange rate: {exchange_rate.value}"
    if fiat_currency == "USD":
        fiat_value_usd = raw_fiat_value
    else:
        to_currency = models.Currency.USD
        exchange_rate = prices.get_closest_exchange_rate(
            executed_at.date(), from_currency, to_currency
        )
        if exchange_rate is None:
            raise CurrencyMismatch(
                "Couldn't convert the fiat to USD, missing exchange rate"
            )
        fiat_value_usd = raw_fiat_value * exchange_rate.value

    quantity = to_decimal(token_record["Change"])
    with decimal.localcontext() as c:
        c.prec = 10
        price = decimal.Decimal(-fiat_value_usd / quantity)

    return (
        *accounts.AccountRepository().add_transaction_crypto_asset(
            account,
            symbol,
            executed_at,
            quantity,
            price,
            fiat_value_usd,
            fiat_value,
            fiat_value,
        ),
        raw_record,
    )
예제 #2
0
def import_transaction(
    account: models.Account,
    transaction_record: pd.Series,
    import_all_assets,
) -> Tuple[models.Transaction, bool]:
    executed_at = transaction_record["Datetime"]
    isin = transaction_record["ISIN"]
    local_value = transaction_record["Local value"]
    total_in_account_currency = transaction_record["Total"]
    value_in_account_currency = transaction_record["Value"]
    transaction_costs = transaction_record["Transaction costs"].astype(str)
    order_id = transaction_record["Order ID"]
    quantity = transaction_record["Quantity"]
    price = transaction_record["Price"]
    account_currency = transaction_record["Value currency"]
    local_currency = transaction_record["Local value currency"]
    product = transaction_record["Product"]

    if models.currency_enum_from_string(account_currency) != account.currency:
        raise CurrencyMismatch("Currency of import didn't match the account")
    exchange_mic = transaction_record["Venue"]
    exchange_ref = transaction_record["Reference"]
    try:
        exchange = stock_exchanges.ExchangeRepository().get(
            exchange_mic, exchange_ref)
    except Exception as e:
        logger.error(e)
        raise e

    def to_decimal(pd_f):
        return decimal.Decimal(pd_f.astype(str))

    transaction_costs = decimal.Decimal(transaction_costs)
    if transaction_costs.is_nan():
        transaction_costs = None
    return accounts.AccountRepository().add_transaction(
        account,
        isin=isin,
        exchange=exchange,
        executed_at=executed_at,
        quantity=to_decimal(quantity),
        price=to_decimal(price),
        transaction_costs=transaction_costs,
        local_value=to_decimal(local_value),
        value_in_account_currency=to_decimal(value_in_account_currency),
        total_in_account_currency=to_decimal(total_in_account_currency),
        order_id=order_id,
        asset_defaults={
            "local_currency": local_currency,
            "name": product
        },
        import_all_assets=import_all_assets,
    )
예제 #3
0
 def test_adding_account(self, nickname, currency):
     self.client.force_login(self.user)
     response = self.client.post(
         reverse(self.VIEW_NAME),
         {
             "currency": currency,
             "nickname": nickname,
             "description": "",
         },
     )
     self.assertEqual(response.status_code, 201)
     self.assertEqual(models.Account.objects.count(), 2)
     account = models.Account.objects.get(
         currency=models.currency_enum_from_string(currency),
         nickname=nickname,
     )
     self.assertEqual(account.user, self.user)
예제 #4
0
def import_fiat_transfers(account, records):
    account_repository = accounts.AccountRepository()
    successful_records = []

    for record in records.iloc:
        raw_record = record.to_csv()
        event_type = models.EventType.DEPOSIT
        if record["Operation"] == "Withdrawal":
            event_type = models.EventType.WITHDRAWAL
        executed_at = _parse_utc_datetime(record["UTC_Time"])

        fiat_currency = record["Coin"]
        fiat_value = to_decimal(record["Change"])

        if fiat_currency != models.Currency(account.currency).label:
            from_currency = models.currency_enum_from_string(fiat_currency)
            to_currency = account.currency
            exchange_rate = prices.get_closest_exchange_rate(
                executed_at.date(), from_currency, to_currency
            )
            if exchange_rate is None:
                raise CurrencyMismatch(
                    "Couldn't convert the fiat to account currency, missing exchange rate"
                )
            else:
                fiat_value *= exchange_rate.value
            raw_record += f", exchange rate: {exchange_rate.value}"

        event, created = account_repository.add_event(
            account,
            amount=fiat_value,
            executed_at=executed_at,
            event_type=event_type,
        )
        successful_records.append(
            {
                "record": raw_record,
                "event": event,
                "transaction": None,
                "created": created,
            }
        )
    return successful_records
예제 #5
0
 def validate_to_currency(self, value):
     try:
         return models.currency_enum_from_string(value)
     except ValueError:
         raise serializers.ValidationError(
             f"{value} is not a valid currency symbol")
예제 #6
0
def _to_currency(currency_raw: str) -> Optional[models.Currency]:
    try:
        return models.currency_enum_from_string(currency_raw)
    except ValueError:
        return
예제 #7
0
def get_or_create_asset(
    isin: str,
    exchange: models.Exchange,
    asset_defaults,
    add_untracked_if_not_found,
    user,
):
    repository = AssetRepository(exchange)
    asset = repository.get(isin)
    if asset:
        return asset
    if exchange.name != OTHER_OR_NA_EXCHANGE_NAME:
        exchange_code = exchange.identifiers.get(
            id_type=models.ExchangeIDType.CODE).value
    else:
        exchange_code = ""
    asset_records = query_asset(isin)
    for record in asset_records:
        if record["Exchange"] == exchange_code:
            asset_type_raw = record["Type"]
            if asset_defaults["local_currency"] != record["Currency"]:
                # There could be multiple assets registered with the same ISIN, but different currencies.
                continue
            currency = models.currency_enum_from_string(record["Currency"])
            asset = repository.add(
                isin=isin,
                symbol=record["Code"],
                currency=currency,
                country=record["Country"],
                name=record["Name"],
                tracked=True,
                user=user,
                asset_type=_to_asset_type(asset_type_raw),
            )
            print("created asset")
            return asset
    else:
        if len(asset_records):
            record = asset_records[0]
            asset_type_raw = record["Type"]
            currency = models.currency_enum_from_string(
                asset_defaults["local_currency"])
            if add_untracked_if_not_found:
                asset = repository.add(
                    isin=isin,
                    symbol=record["Code"],
                    currency=currency,
                    country=record["Country"],
                    name=record["Name"],
                    tracked=False,
                    user=user,
                    asset_type=_to_asset_type(asset_type_raw),
                )

                return asset
            logging.warn(
                f"failed to find stock data for isin: {isin}, exchange: {exchange}, exchange_code: {exchange_code}"
            )
        else:
            if add_untracked_if_not_found:
                currency = models.currency_enum_from_string(
                    asset_defaults["local_currency"])
                asset = repository.add(
                    isin=isin,
                    symbol=isin,
                    currency=currency,
                    country="Unknown",
                    name=asset_defaults["name"],
                    tracked=False,
                    user=user,
                    asset_type=models.AssetType.STOCK,
                )
                return asset
            logging.warn(
                f"failed to find stock data (there were assets but no exchange match) for isin: {isin}, exchange: {exchange}, exchange_code: {exchange_code}"
            )