159 lines
5.2 KiB
PHP
159 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use CodeIgniter\Model;
|
|
|
|
class InstrumentModel extends Model
|
|
{
|
|
protected $table = 'inv_instruments';
|
|
protected $primaryKey = 'id';
|
|
protected $returnType = 'array';
|
|
protected $useTimestamps = true;
|
|
protected $allowedFields = ['name'];
|
|
|
|
protected $validationRules = [
|
|
'name' => 'required|max_length[120]',
|
|
];
|
|
|
|
/**
|
|
* Czy instrument ma powiazane operacje lub wyceny (blokada usuniecia).
|
|
*/
|
|
public function hasChildren(int $id): bool
|
|
{
|
|
$ops = (int) $this->db->table('inv_operations')->where('instrument_id', $id)->countAllResults();
|
|
$val = (int) $this->db->table('inv_valuations')->where('instrument_id', $id)->countAllResults();
|
|
|
|
return ($ops + $val) > 0;
|
|
}
|
|
|
|
/**
|
|
* Ostatnia wycena per instrument: [instrument_id => value].
|
|
* Ostatnia = najpozniejsza data, przy remisie najwyzsze id.
|
|
*/
|
|
private function latestValuations(): array
|
|
{
|
|
$rows = $this->db->table('inv_valuations')
|
|
->select('instrument_id, value')
|
|
->orderBy('instrument_id', 'ASC')->orderBy('date', 'ASC')->orderBy('id', 'ASC')
|
|
->get()->getResultArray();
|
|
|
|
$latest = [];
|
|
foreach ($rows as $r) {
|
|
$latest[(int) $r['instrument_id']] = (float) $r['value']; // ostatni wygrywa (posortowane rosnaco)
|
|
}
|
|
|
|
return $latest;
|
|
}
|
|
|
|
/**
|
|
* Sumy wplat/wyplat per instrument: [instrument_id => ['deposit'=>..,'withdraw'=>..]].
|
|
*/
|
|
private function operationSums(): array
|
|
{
|
|
$rows = $this->db->table('inv_operations')
|
|
->select('instrument_id')
|
|
->select("SUM(CASE WHEN type='deposit' THEN amount ELSE 0 END) AS deposit")
|
|
->select("SUM(CASE WHEN type='withdraw' THEN amount ELSE 0 END) AS withdraw")
|
|
->groupBy('instrument_id')
|
|
->get()->getResultArray();
|
|
|
|
$sums = [];
|
|
foreach ($rows as $r) {
|
|
$sums[(int) $r['instrument_id']] = [
|
|
'deposit' => (float) $r['deposit'],
|
|
'withdraw' => (float) $r['withdraw'],
|
|
];
|
|
}
|
|
|
|
return $sums;
|
|
}
|
|
|
|
/**
|
|
* Instrumenty ze statystykami:
|
|
* wplacone_netto = Sumwplat - Sumwyplat; wartosc = ostatnia wycena;
|
|
* zarobek = wartosc - wplacone_netto; procent = zarobek / wplacone_netto * 100 (gdy netto > 0).
|
|
*/
|
|
public function withStats(): array
|
|
{
|
|
$instruments = $this->orderBy('name', 'ASC')->findAll();
|
|
$latest = $this->latestValuations();
|
|
$sums = $this->operationSums();
|
|
|
|
foreach ($instruments as &$ins) {
|
|
$id = (int) $ins['id'];
|
|
$deposit = $sums[$id]['deposit'] ?? 0.0;
|
|
$withdraw = $sums[$id]['withdraw'] ?? 0.0;
|
|
$net = $deposit - $withdraw;
|
|
$value = $latest[$id] ?? 0.0;
|
|
$profit = $value - $net;
|
|
|
|
$ins['deposit'] = round($deposit, 2);
|
|
$ins['withdraw'] = round($withdraw, 2);
|
|
$ins['net_invested'] = round($net, 2);
|
|
$ins['value'] = round($value, 2);
|
|
$ins['has_value'] = array_key_exists($id, $latest);
|
|
$ins['profit'] = round($profit, 2);
|
|
$ins['percent'] = $net > 0 ? round($profit / $net * 100, 2) : null;
|
|
}
|
|
|
|
return $instruments;
|
|
}
|
|
|
|
/**
|
|
* Szereg czasowy calego portfela do wykresu.
|
|
* Dla kazdej daty wyceny: wartosc = suma ostatnich wycen (data <= d) po instrumentach;
|
|
* wplacone_netto = Sum(deposit - withdraw) o dacie <= d; zarobek = wartosc - wplacone_netto.
|
|
* Zwraca [ ['date'=>.., 'net'=>.., 'value'=>.., 'profit'=>..], ... ].
|
|
*/
|
|
public function portfolioTimeline(): array
|
|
{
|
|
$dates = $this->db->table('inv_valuations')
|
|
->select('date')->distinct()->orderBy('date', 'ASC')
|
|
->get()->getResultArray();
|
|
if (empty($dates)) {
|
|
return [];
|
|
}
|
|
|
|
$valuations = $this->db->table('inv_valuations')
|
|
->select('instrument_id, date, value')
|
|
->orderBy('date', 'ASC')->orderBy('id', 'ASC')
|
|
->get()->getResultArray();
|
|
|
|
$operations = $this->db->table('inv_operations')
|
|
->select('date, amount, type')
|
|
->get()->getResultArray();
|
|
|
|
$out = [];
|
|
foreach ($dates as $d) {
|
|
$day = $d['date'];
|
|
|
|
// Ostatnia wycena per instrument o dacie <= day
|
|
$latest = [];
|
|
foreach ($valuations as $v) {
|
|
if ($v['date'] <= $day) {
|
|
$latest[(int) $v['instrument_id']] = (float) $v['value'];
|
|
}
|
|
}
|
|
$value = array_sum($latest);
|
|
|
|
// Wplacone netto o dacie <= day
|
|
$net = 0.0;
|
|
foreach ($operations as $o) {
|
|
if ($o['date'] <= $day) {
|
|
$net += $o['type'] === 'deposit' ? (float) $o['amount'] : -(float) $o['amount'];
|
|
}
|
|
}
|
|
|
|
$out[] = [
|
|
'date' => $day,
|
|
'net' => round($net, 2),
|
|
'value' => round($value, 2),
|
|
'profit' => round($value - $net, 2),
|
|
];
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
}
|