summaryrefslogtreecommitdiff
path: root/src/FundLab.Api/App.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 03:25:00 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 03:25:00 +0800
commit7dd0e3f42105569b6e6ec02aeeec9b5a8bbd9dd3 (patch)
treed7374c1b4bb5308374c3386ac3768ac7209a6440 /src/FundLab.Api/App.fs
parent8c01adf05f1428bf2ada49574b25529c064da884 (diff)
downloadfund-lab-7dd0e3f42105569b6e6ec02aeeec9b5a8bbd9dd3.tar.gz
Add real AKShare stock daily history probe slice (3d-19)
Diffstat (limited to 'src/FundLab.Api/App.fs')
-rw-r--r--src/FundLab.Api/App.fs52
1 files changed, 51 insertions, 1 deletions
diff --git a/src/FundLab.Api/App.fs b/src/FundLab.Api/App.fs
index 9565485..4313329 100644
--- a/src/FundLab.Api/App.fs
+++ b/src/FundLab.Api/App.fs
@@ -358,6 +358,7 @@ type MarketProbes =
NavSeries: INavSeriesProbe
BondQuotes: IBondQuoteProbe
StockQuotes: IStockQuoteProbe
+ StockDaily: IStockDailyProbe
}
type BondQuoteApiResponse =
@@ -376,6 +377,20 @@ type StockQuoteApiResponse =
currency: string
}
+type StockDailyObservationApiResponse =
+ {
+ date: string
+ close: string
+ volume: string option
+ amount: string option
+ }
+
+type StockDailyApiResponse =
+ {
+ code: string
+ observations: StockDailyObservationApiResponse list
+ }
+
module App =
let addOptionFriendlyJson (services: IServiceCollection) =
let settings =
@@ -1630,7 +1645,7 @@ module App =
lastSeenAt = timestampText observation.LastSeenAt
}
- let private marketDataNavResponse code observations =
+ let private marketDataNavResponse code (observations: MarketDataNavRecord list) : MarketDataNavApiResponse =
{
code = code
observations = observations |> List.map marketDataObservationResponse
@@ -1753,12 +1768,47 @@ module App =
ctx
| Error failure -> marketDataError failure next ctx
+ let private stockDailyObservationResponse (observation: StockDailyObservation) : StockDailyObservationApiResponse =
+ {
+ date = dateText observation.BarDate
+ close = decimalText observation.Close
+ volume = observation.Volume |> Option.map decimalText
+ amount = observation.Amount |> Option.map decimalText
+ }
+
+ let private getStockDaily (probe: IStockDailyProbe) : HttpHandler =
+ fun next ctx ->
+ let code = ctx.Request.Query["code"].ToString()
+ let daysText = ctx.Request.Query["days"].ToString()
+
+ let days =
+ if String.IsNullOrWhiteSpace daysText then
+ Ok 5
+ else
+ match Int32.TryParse(daysText, NumberStyles.Integer, invariant) with
+ | true, value when value >= 1 && value <= 30 -> Ok value
+ | _ -> Error "days must be an integer between 1 and 30"
+
+ match days with
+ | Error message -> marketDataError (InvalidMarketDataRequest message) next ctx
+ | Ok value ->
+ match probe.RecentDaily(code, value, ctx.RequestAborted) with
+ | Ok observations ->
+ json
+ ({ code = code.Trim()
+ observations = observations |> List.map stockDailyObservationResponse }
+ : StockDailyApiResponse)
+ next
+ ctx
+ | Error failure -> marketDataError failure next ctx
+
let private marketProbeRoutes (probes: MarketProbes) =
[
GET >=> route "/market/nav-dates" >=> getMarketNavDates probes.NavDates
GET >=> route "/market/nav-series" >=> getMarketNavSeries probes.NavSeries
GET >=> route "/market/bond-quote" >=> getBondQuote probes.BondQuotes
GET >=> route "/market/stock-quote" >=> getStockQuote probes.StockQuotes
+ GET >=> route "/market/stock-daily" >=> getStockDaily probes.StockDaily
]
let private createApplicationInternal