fix: multi currency seeders
This commit is contained in:
+18
-14
@@ -111,7 +111,7 @@ class CurrencyRate extends Model
|
|||||||
*
|
*
|
||||||
* @return array<string, float>
|
* @return array<string, float>
|
||||||
*/
|
*/
|
||||||
public static function timeSeriesRates(string|array $currency, mixed $start = null, mixed $end = null): array
|
public static function timeSeriesRates(?string $currency = null, mixed $start = null, mixed $end = null): array
|
||||||
{
|
{
|
||||||
if (empty($start)) {
|
if (empty($start)) {
|
||||||
return [];
|
return [];
|
||||||
@@ -132,19 +132,18 @@ class CurrencyRate extends Model
|
|||||||
return $dateRange;
|
return $dateRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
[$currency, $adjustment] = self::getCurrencyAliasAdjustments($currency);
|
// handle currency alias
|
||||||
|
|
||||||
if (! empty($currency)) {
|
if (! empty($currency)) {
|
||||||
|
|
||||||
$currencies = Arr::wrap($currency);
|
[$currency, $adjustment] = self::getCurrencyAliasAdjustments($currency);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$currencies = Currency::all()->pluck('currency')->toArray();
|
$currency = Currency::all()->pluck('currency')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get rates
|
// get rates
|
||||||
$rates = Frankfurter::setSymbols($currencies)->timeSeries($period->first(), $period->last());
|
$rates = Frankfurter::setSymbols($currency)->timeSeries($period->first(), $period->last());
|
||||||
|
|
||||||
$rates = collect(Arr::get($rates, 'rates', []))->sortKeys()->toArray();
|
$rates = collect(Arr::get($rates, 'rates', []))->sortKeys()->toArray();
|
||||||
|
|
||||||
@@ -177,13 +176,18 @@ class CurrencyRate extends Model
|
|||||||
// persist
|
// persist
|
||||||
self::chunkInsert($updates);
|
self::chunkInsert($updates);
|
||||||
|
|
||||||
return collect($updates)
|
if (is_string($currency)) {
|
||||||
->whereBetween('date', [$start, $end ?? now()])
|
|
||||||
->where('currency', $currency)
|
return collect($updates)
|
||||||
->mapWithKeys(fn ($rate) => [
|
->whereBetween('date', [$start, $end ?? now()])
|
||||||
$rate['date'] => $rate['rate'] * $adjustment,
|
->where('currency', $currency)
|
||||||
])
|
->mapWithKeys(fn ($rate) => [
|
||||||
->toArray();
|
$rate['date'] => $rate['rate'] * ($adjustment ?? 1),
|
||||||
|
])
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getNearestPastDate(CarbonInterface $date, array $datesOnly, array $rates): ?CarbonInterface
|
private static function getNearestPastDate(CarbonInterface $date, array $datesOnly, array $rates): ?CarbonInterface
|
||||||
@@ -265,7 +269,7 @@ class CurrencyRate extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function getCurrencyAliasAdjustments($currency)
|
protected static function getCurrencyAliasAdjustments(string $currency)
|
||||||
{
|
{
|
||||||
$adjustment = 1;
|
$adjustment = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,14 @@ return new class extends Migration
|
|||||||
'--force' => true,
|
'--force' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
CurrencyRate::timeSeriesRates(
|
Holding::all()->groupBy('market_data.currency')->keys()->each(
|
||||||
Holding::all()->groupBy('market_data.currency')->keys()->toArray(),
|
fn ($currency) => dispatch(
|
||||||
Transaction::min('date')
|
function () use ($currency) {
|
||||||
|
CurrencyRate::timeSeriesRates(
|
||||||
|
$currency,
|
||||||
|
Transaction::min('date')
|
||||||
|
);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
CurrencyRate::refreshCurrencyData();
|
CurrencyRate::refreshCurrencyData();
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ class MarketDataSeeder extends Seeder
|
|||||||
$rowCount++;
|
$rowCount++;
|
||||||
|
|
||||||
if ($rowCount % $chunkSize == 0) {
|
if ($rowCount % $chunkSize == 0) {
|
||||||
DB::table('market_data')->upsert($this->rows, ['symbol'], ['name', 'currency', 'meta_data']);
|
$this->bulkInsert($this->rows);
|
||||||
$this->rows = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,11 +76,14 @@ class MarketDataSeeder extends Seeder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bulkInsert(array $rows)
|
public function bulkInsert($rows)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
DB::table('market_data')->insertOrIgnore($rows);
|
dispatch(
|
||||||
|
fn () => DB::table('market_data')->upsert($rows, ['symbol'], ['name', 'currency', 'meta_data'])
|
||||||
|
);
|
||||||
|
|
||||||
$this->rows = [];
|
$this->rows = [];
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ class MarketDataTest extends TestCase
|
|||||||
'--force' => true,
|
'--force' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(14464, MarketData::count('symbol'));
|
$this->assertEquals(14262, MarketData::count('symbol'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_can_get_quote_from_provider()
|
public function test_can_get_quote_from_provider()
|
||||||
|
|||||||
@@ -225,8 +225,40 @@ class MultiCurrencyTest extends TestCase
|
|||||||
->andReturn(['rates' => $results]);
|
->andReturn(['rates' => $results]);
|
||||||
|
|
||||||
$result = CurrencyRate::timeSeriesRates('ZZZ', $start, $end);
|
$result = CurrencyRate::timeSeriesRates('ZZZ', $start, $end);
|
||||||
|
|
||||||
$this->assertEquals(count($period) - 1, count($result));
|
$this->assertEquals(count($period) - 1, count($result));
|
||||||
|
|
||||||
|
$result = CurrencyRate::all();
|
||||||
|
$this->assertEquals(count($period), count($result));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_can_get_time_series_rates_with_null_currency()
|
||||||
|
{
|
||||||
|
|
||||||
|
$start = now()->subWeeks(2);
|
||||||
|
$end = now();
|
||||||
|
|
||||||
|
$period = CarbonPeriod::create($start, $end);
|
||||||
|
|
||||||
|
// mock response from Frankfurter
|
||||||
|
$results = [];
|
||||||
|
collect($period->copy()->filter('isWeekday'))->each(function ($date) use (&$results) {
|
||||||
|
$date = $date->toDateString();
|
||||||
|
|
||||||
|
$results[$date] = [
|
||||||
|
'FOO' => random_int(10, 150) / 1000,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
Frankfurter::expects('setSymbols')
|
||||||
|
->andReturnSelf();
|
||||||
|
Frankfurter::expects('timeSeries')
|
||||||
|
->andReturn(['rates' => $results]);
|
||||||
|
|
||||||
|
$result = CurrencyRate::timeSeriesRates(null, $start, $end);
|
||||||
|
$this->assertEquals(0, count($result));
|
||||||
|
|
||||||
|
$result = CurrencyRate::all();
|
||||||
|
$this->assertEquals(count($period), count($result));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_time_series_rate_calls_are_chunked()
|
public function test_time_series_rate_calls_are_chunked()
|
||||||
|
|||||||
Reference in New Issue
Block a user