diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-22 01:12:52 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-22 01:12:52 +0800 |
| commit | 3cc0b4dcfeed042e5a69628c6b7f45580ad1e2f9 (patch) | |
| tree | b86805c2680327412d6f5d554d4506ebfe62fc2f /src/FundLab.Api/MarketData.fs | |
| parent | 70e1ad4fc8ba248f835d415faade8a91ac3dc1f8 (diff) | |
| download | fund-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.fs | 62 |
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" |
