TradeMind / data /commodity_pricing.py
KSS-1227's picture
some pushes
a02845e
Raw History Blame Contribute Delete
2.34 kB
"""Deterministic commodity unit and INR conversion helpers.
External COMEX quotes are USD per troy ounce. These helpers convert that
explicit unit into an indicative Indian landed value; they do not claim to be
an MCX settlement or a jeweller's retail quote.
"""
from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_UP
from typing import Union
Number = Union[Decimal, int, float, str]
TROY_OUNCE_GRAMS = Decimal("31.1034768")
GOLD_IMPORT_DUTY_RATE = Decimal("0.06")
GST_RATE = Decimal("0.03")
GRAMS_PER_10_GRAMS = Decimal("10")
GRAMS_PER_KILOGRAM = Decimal("1000")
@dataclass(frozen=True)
class CommodityConversion:
"""Auditable values for a USD/troy-ounce to INR conversion."""
raw_usd_per_troy_ounce: Decimal
usd_to_inr: Decimal
inr_per_gram_before_taxes: Decimal
inr_per_display_unit: Decimal
def usd_per_troy_ounce_to_indian_landed_price(
raw_usd_per_troy_ounce: Number,
usd_to_inr: Number,
grams_per_display_unit: Number,
import_duty_rate: Decimal = GOLD_IMPORT_DUTY_RATE,
gst_rate: Decimal = GST_RATE,
) -> CommodityConversion:
"""Convert USD/troy oz to INR for a declared gram-based display unit.
Tax is applied once, sequentially: import duty first, then GST. Decimal
inputs prevent binary floating-point rounding from leaking into prices.
"""
raw_price = _decimal(raw_usd_per_troy_ounce)
exchange_rate = _decimal(usd_to_inr)
display_grams = _decimal(grams_per_display_unit)
if raw_price < 0 or exchange_rate <= 0 or display_grams <= 0:
raise ValueError("Commodity price, FX rate, and display grams must be positive.")
inr_per_gram = raw_price * exchange_rate / TROY_OUNCE_GRAMS
tax_multiplier = (Decimal("1") + import_duty_rate) * (Decimal("1") + gst_rate)
inr_per_display_unit = inr_per_gram * display_grams * tax_multiplier
return CommodityConversion(
raw_usd_per_troy_ounce=raw_price,
usd_to_inr=exchange_rate,
inr_per_gram_before_taxes=inr_per_gram,
inr_per_display_unit=inr_per_display_unit,
)
def rounded_inr(value: Decimal) -> float:
"""Round a Decimal currency value to paise for JSON responses."""
return float(value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
def _decimal(value: Number) -> Decimal:
return Decimal(str(value))