external_account_id) { return; } $investedAmountCents = $this->calculateInvestedAmount($client, strtoupper($account->currency_code)); $this->syncCurrentBalance($account, $client, $investedAmountCents); } /** * Sync today's balance by fetching all wallets and converting to target currency * using Bitpanda's own ticker prices. */ public function syncCurrentBalance(Account $account, BitpandaClient $client, ?int $investedAmountCents = null): void { $targetCurrency = strtoupper($account->currency_code); $ticker = $client->getTickerPrices(); $totalValue = 0.0; $totalValue += $this->sumCryptoWallets($client, $ticker, $targetCurrency); $totalValue += $this->sumFiatWallets($client, $targetCurrency); $totalValueCents = (int) round($totalValue * 100); $account->balances()->updateOrCreate( ['balance_date' => now()->toDateString()], [ 'balance' => $totalValueCents, ...($investedAmountCents !== null ? ['invested_amount' => $investedAmountCents] : []), ], ); } /** * Sum all crypto wallet balances using Bitpanda's ticker prices. * * @param array> $ticker */ private function sumCryptoWallets(BitpandaClient $client, array $ticker, string $targetCurrency): float { $wallets = $client->getCryptoWallets(); $total = 0.0; foreach ($wallets['data'] as $wallet) { $attributes = $wallet['attributes']; $balance = (float) $attributes['balance']; $symbol = $attributes['cryptocoin_symbol']; $deleted = $attributes['deleted']; if ($balance <= 0 || ! $symbol || $deleted) { continue; } $price = $this->getTickerPrice($ticker, $symbol, $targetCurrency); if ($price === null) { Log::warning('Bitpanda ticker price not found for asset', [ 'asset' => $symbol, 'target_currency' => $targetCurrency, ]); continue; } $total += $balance * $price; } return $total; } /** * Sum all fiat wallet balances, using ticker to convert if needed. */ private function sumFiatWallets(BitpandaClient $client, string $targetCurrency): float { $wallets = $client->getFiatWallets(); $total = 0.0; foreach ($wallets['data'] as $wallet) { $attributes = $wallet['attributes']; $balance = (float) $attributes['balance']; $symbol = strtoupper($attributes['fiat_symbol']); if ($balance <= 0 || ! $symbol) { continue; } if ($symbol === $targetCurrency) { $total += $balance; } else { // Fiat-to-fiat conversion is rare on Bitpanda; use simple rate if available Log::warning('Bitpanda fiat wallet in different currency than target', [ 'fiat_symbol' => $symbol, 'target_currency' => $targetCurrency, 'balance' => $balance, ]); } } return $total; } /** * Get the ticker price for an asset in the target currency. * * @param array> $ticker */ private function getTickerPrice(array $ticker, string $symbol, string $targetCurrency): ?float { $price = $ticker[$symbol][$targetCurrency] ?? null; if ($price === null) { return null; } return (float) $price; } /** * Calculate net invested amount from fiat deposit and withdrawal history. * Net invested = total deposits - total withdrawals (in cents). */ private function calculateInvestedAmount(BitpandaClient $client, string $targetCurrency): ?int { $deposits = $client->getAllFiatTransactions('deposit'); $withdrawals = $client->getAllFiatTransactions('withdrawal'); $totalDeposited = $this->sumFiatTransactions($deposits, $targetCurrency); $totalWithdrawn = $this->sumFiatTransactions($withdrawals, $targetCurrency); if ($totalDeposited === 0.0 && $totalWithdrawn === 0.0) { return null; } return (int) round(($totalDeposited - $totalWithdrawn) * 100); } /** * Sum the amounts of fiat transactions in the target currency. * Only considers finished transactions whose fiat_id matches the target currency. * * @param array $transactions */ private function sumFiatTransactions(array $transactions, string $targetCurrency): float { $total = 0.0; foreach ($transactions as $transaction) { $attributes = $transaction['attributes']; $status = $attributes['status'] ?? ''; $amount = (float) ($attributes['amount'] ?? 0); if ($status !== 'finished' || $amount <= 0) { continue; } $fiatId = strtoupper($attributes['fiat_id'] ?? ''); if ($fiatId !== $targetCurrency) { Log::warning('Bitpanda fiat transaction in different currency than target', [ 'fiat_id' => $fiatId, 'target_currency' => $targetCurrency, 'amount' => $amount, ]); continue; } $total += $amount; } return $total; } }