diff options
Diffstat (limited to 'src/FundLab.Api/App.fs')
| -rw-r--r-- | src/FundLab.Api/App.fs | 52 |
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 |
