Documentation
¶
Overview ¶
Package money is the leaf-layer Money value object.
Why a separate package: the existing Slice 1-6d Money sweep placed the type in kc/domain. That worked for in-process consumers but blocked Slice 6e (broker.Holding.PnL / broker.Position.PnL elevated to Money) — the broker package can't import kc/domain because kc/domain itself imports broker for its Holding / Position / Order wrapper entities, and Go forbids the resulting cycle.
Extracting Money to a leaf package (zero internal repo deps) lets both kc/domain and broker import it freely. kc/domain.Money is now a type alias to money.Money so the 65+ existing consumer files (372+ constructor sites, struct literals, method calls) continue to compile unchanged. The alias is structural, not behavioural — downstream code observes identical semantics.
Wire-format choice (MarshalJSON / UnmarshalJSON):
- INR Money serializes as a bare JSON number (1234.56). This is the pre-Slice-6e wire shape for broker.Holding.PnL etc.; keeping it bare-float means external Kite-API-shaped consumers see no schema break.
- Non-INR Money serializes as {"amount":N,"currency":"S"}. The cross-currency case is rare in practice (gokiteconnect emits INR-only) but the explicit shape removes ambiguity for forward- compat multi-currency accounts.
- UnmarshalJSON accepts BOTH shapes symmetrically: a bare number rehydrates as INR; an object preserves the currency tag.
Empty Currency on a zero-value Money is the "no money set" sentinel — IsZero() / IsPositive() / IsNegative() are the canonical predicates. Empty Currency does NOT auto-INR at construction (zero-value safety), but bare-float JSON DOES auto-INR on unmarshal (wire-compat).
Index ¶
- type Money
- func (m Money) Add(other Money) (Money, error)
- func (m Money) Float64() float64
- func (m Money) GreaterThan(other Money) (bool, error)
- func (m Money) IsNegative() bool
- func (m Money) IsPositive() bool
- func (m Money) IsZero() bool
- func (m Money) MarshalJSON() ([]byte, error)
- func (m Money) Multiply(factor float64) Money
- func (m Money) String() string
- func (m Money) Sub(other Money) (Money, error)
- func (m *Money) UnmarshalJSON(data []byte) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Money ¶
Money is a value object representing a monetary amount with currency. The default and primary currency is INR.
func NewINR ¶
NewINR creates a Money value in Indian Rupees without validation. Kept for existing callers that intentionally pass zero/negative values (adjustments, PnL deltas). New call sites that must reject invalid amounts should prefer NewMoney.
func NewMoney ¶
NewMoney creates a validated Money value in INR. Rejects amounts that are not strictly positive — the canonical "price must be > 0" invariant for LIMIT/SL orders. Zero is rejected so that the zero-value Money can be detected as "no price set" via IsPositive.
func (Money) Add ¶
Add returns a new Money that is the sum of m and other. Returns an error if the currencies differ.
func (Money) Float64 ¶
Float64 returns the underlying amount. Boundary accessor for JSON serialization, log fields, and SQLite REAL bindings — call sites that invoke this are deliberately crossing out of the domain layer. New in-domain code should keep working with Money values directly.
func (Money) GreaterThan ¶
GreaterThan reports whether m's amount is strictly greater than other's. Returns an error if the currencies differ — silent cross-currency comparison would defeat the type's purpose (e.g. comparing a USD limit against an INR order value would silently coerce). The riskguard per-user MaxSingleOrderINR / MaxDailyValueINR caps use this method.
func (Money) IsNegative ¶
IsNegative returns true if the amount is less than zero.
func (Money) IsPositive ¶
IsPositive returns true if the amount is greater than zero.
func (Money) MarshalJSON ¶
MarshalJSON implements json.Marshaler. Wire-compat choice (Slice 6e precondition): INR Money + zero-value Money serialize as a bare JSON number to match the pre-Money-typed broker DTO wire shape; non-INR Money serializes as an explicit {"amount", "currency"} object so cross-currency cases are unambiguous on the wire.
Justification: 372+ constructor call sites currently emit Money via the kc/domain package. Those that cross JSON boundaries (broker DTOs post-Slice-6e, billing.Subscription) use INR almost exclusively (gokiteconnect emits INR; billing tiers are INR by tier table). Bare-float emission means downstream consumers see no schema break. The non-INR object shape is reserved for the small future multi- currency surface.
func (Money) String ¶
String formats the money for display. INR is rendered as "₹1,234.56"; other currencies use the ISO code prefix.
func (Money) Sub ¶
Sub returns a new Money that is m minus other. Returns an error if the currencies differ.
func (*Money) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler symmetric to MarshalJSON: a bare JSON number rehydrates as an INR Money (matches the bare-float emission); an object with "amount" + "currency" keys preserves the currency tag. This is the read-side guarantee that historical rows (pre-Slice-6e, all bare floats) round-trip correctly into the new Money-typed broker DTOs.