Files
links/invest/forms.py
T
OpenClaw Sub-agent b67a834def feat(invest): cost basis & P&L, AUD totals, chart ranges, per-ticker page, manual entry, tx search
P1:
- WAC cost basis per (portfolio, ticker): avg_cost / unrealized P&L / P&L%
  - transaction price when recorded, else trade-date market close (estimated, flagged)
  - dashboard: Unrealized P&L card + Avg Cost & P&L columns on holdings tables
  - fx: frankfurter.dev rates (USD/HKD->AUD, 24h cache, UA header required) -> AUD total on Total Value card
  - chart: 1M/3M/6M/YTD/1Y/ALL period buttons (all periods precomputed server-side, top-level payload stays YTD for compat)
P2:
- /invest/stocks/<ticker>/ per-ticker page: cross-account holdings, WAC, P&L, weight, theme, trade history
- manual transaction + cashflow entry forms (source=MANUAL, confidence=1.0)
- dashboard transaction search (?q= ticker/account) + add-transaction buttons
- tickers link to detail page; tabular-nums on all figures
- 8 new tests (WAC sell, estimated price, incomplete, per-portfolio agg, stock page, forms, search)
2026-08-02 08:09:58 +10:00

69 lines
2.6 KiB
Python

"""Forms for manual invest data entry (transactions & cash flows)."""
from django import forms
from .models import CashFlow, Portfolio, Transaction
class TransactionForm(forms.ModelForm):
class Meta:
model = Transaction
fields = [
'portfolio', 'action', 'stock_code', 'quantity',
'price_per_share', 'currency', 'fee', 'date',
]
widgets = {
'date': forms.DateInput(attrs={'type': 'date'}),
'stock_code': forms.TextInput(attrs={'placeholder': '如 NVDA / 9988.HK', 'autocomplete': 'off'}),
'quantity': forms.NumberInput(attrs={'step': '0.000001', 'min': '0.000001'}),
'price_per_share': forms.NumberInput(attrs={'step': '0.000001', 'min': '0', 'placeholder': '可空(用当日收盘价估算)'}),
'fee': forms.NumberInput(attrs={'step': '0.01', 'min': '0', 'placeholder': '可空'}),
}
labels = {
'portfolio': '账户',
'action': '类型',
'stock_code': '股票代码',
'quantity': '数量',
'price_per_share': '成交价(可空)',
'currency': '币种',
'fee': '手续费(可空)',
'date': '日期',
}
help_texts = {
'price_per_share': '留空则按交易日收盘价估算成本',
'fee': '以成交币种计',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['portfolio'].queryset = Portfolio.objects.all()
self.fields['portfolio'].empty_label = None
self.fields['price_per_share'].required = False
self.fields['fee'].required = False
self.fields['currency'].initial = 'USD'
class CashFlowForm(forms.ModelForm):
class Meta:
model = CashFlow
fields = ['portfolio', 'flow_type', 'amount', 'currency', 'date', 'note']
widgets = {
'date': forms.DateInput(attrs={'type': 'date'}),
'amount': forms.NumberInput(attrs={'step': '0.01', 'min': '0.01'}),
'note': forms.TextInput(attrs={'placeholder': '备注(可空)'}),
}
labels = {
'portfolio': '账户',
'flow_type': '类型',
'amount': '金额',
'currency': '币种',
'date': '日期',
'note': '备注',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['portfolio'].queryset = Portfolio.objects.all()
self.fields['portfolio'].empty_label = None
self.fields['currency'].initial = 'USD'
self.fields['note'].required = False