summaryrefslogtreecommitdiff
path: root/src/FundLab.Api/MarketData.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 01:12:52 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 01:12:52 +0800
commit3cc0b4dcfeed042e5a69628c6b7f45580ad1e2f9 (patch)
treeb86805c2680327412d6f5d554d4506ebfe62fc2f /src/FundLab.Api/MarketData.fs
parent70e1ad4fc8ba248f835d415faade8a91ac3dc1f8 (diff)
downloadfund-lab-3cc0b4dcfeed042e5a69628c6b7f45580ad1e2f9.tar.gz
Add real AKShare bond quote probe slice (3d-14)
Diffstat (limited to 'src/FundLab.Api/MarketData.fs')
-rw-r--r--src/FundLab.Api/MarketData.fs62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/FundLab.Api/MarketData.fs b/src/FundLab.Api/MarketData.fs
index e396a7d..ad2a623 100644
--- a/src/FundLab.Api/MarketData.fs
+++ b/src/FundLab.Api/MarketData.fs
@@ -37,6 +37,17 @@ type MarketDataNavPayload =
Observations: MarketDataObservation list
}
+type MarketDataBondQuotePayload =
+ {
+ Source: string
+ SourceRevision: string
+ CollectedAt: DateTimeOffset
+ Code: string
+ Name: string option
+ Price: decimal option
+ MaturityDate: DateOnly option
+ }
+
type MarketDataInstrumentRecord =
{
Code: string
@@ -292,3 +303,54 @@ module MarketData =
}
with
| :? JsonException -> Error "payload must be valid JSON"
+
+ let parseBondQuotePayload (json: string) : Result<MarketDataBondQuotePayload, string> =
+ let optionalIsoDate label (property: JsonElement) =
+ if property.ValueKind = JsonValueKind.Null then
+ Ok None
+ elif property.ValueKind <> JsonValueKind.String then
+ Error(sprintf "%s must be null or an ISO date" label)
+ else
+ let text = property.GetString()
+ let mutable date = DateOnly.MinValue
+
+ if
+ not (String.IsNullOrWhiteSpace text)
+ && DateOnly.TryParseExact(text, "yyyy-MM-dd", invariant, DateTimeStyles.None, &date)
+ then
+ Ok(Some date)
+ else
+ Error(sprintf "%s must be null or an ISO date" label)
+
+ try
+ use document = JsonDocument.Parse(json)
+ let root = document.RootElement
+
+ result {
+ let! source, sourceRevision, collectedAt = validateEnvelope root "bond-quote"
+ let! instrumentProperty = requiredProperty root "instrument"
+ let! codeProperty = requiredString instrumentProperty "code"
+
+ if not (isFundCode codeProperty) then
+ return! Error "bond code must contain exactly six digits"
+
+ let! quoteProperty = requiredProperty root "quote"
+ let! name = optionalString quoteProperty "name"
+ let! priceProperty = requiredProperty quoteProperty "price"
+ let! price = optionalDecimal "price" priceProperty
+ let! maturityProperty = requiredProperty quoteProperty "maturity_date"
+ let! maturityDate = optionalIsoDate "maturity_date" maturityProperty
+
+ return
+ {
+ Source = source
+ SourceRevision = sourceRevision
+ CollectedAt = collectedAt
+ Code = codeProperty
+ Name = name
+ Price = price
+ MaturityDate = maturityDate
+ }
+ }
+ with
+ | :? JsonException -> Error "payload must be valid JSON"