Skip to content

Commit 7331f01

Browse files
authored
Add Jump Start example stock-api-fastapi (#65)
* Add Jump Start example stock-api-fastapi * Bump app version for release * Add minimumConnectVersion
1 parent 25c4454 commit 7331f01

File tree

6 files changed

+12920
-0
lines changed

6 files changed

+12920
-0
lines changed

.github/workflows/extensions.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
quarto-stock-report-python: extensions/quarto-stock-report-python/**
3535
portfolio-dashboard: extensions/portfolio-dashboard/**
3636
quarto-document: extensions/quarto-document/**
37+
stock-api-fastapi: extensions/stock-api-fastapi/**
3738
3839
# Runs for each extension that has changed from `simple-extension-changes`
3940
# Lints and packages in preparation for tests and and release.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# FastAPI Stock Pricing Service
2+
3+
## About this example
4+
5+
An API allows you to turn your models into production services that other tools and teams can use. APIs are a great way for software engineering teams to use your models without translating them into different languages.
6+
7+
8+
## Learn more
9+
10+
* [FastAPI Introduction](https://fastapi.tiangolo.com/)
11+
* [FastAPI Documentation](https://fastapi.tiangolo.com/tutorial/)
12+
13+
## Requirements
14+
15+
* Posit Connect license allows API publishing
16+
* Python version 3.11 or higher
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# -*- coding: utf-8 -*-
2+
import os
3+
from datetime import date
4+
from typing import List
5+
6+
import numpy as np
7+
import pandas as pd
8+
from fastapi import FastAPI, HTTPException
9+
from pydantic import BaseModel, Field
10+
11+
prices = pd.read_csv(
12+
os.path.join(os.path.dirname(__file__), "prices.csv"),
13+
index_col=0,
14+
parse_dates=True,
15+
)
16+
17+
18+
def validate_ticker(ticker):
19+
if ticker not in prices["ticker"].unique():
20+
raise HTTPException(status_code=404, detail="Ticker not found")
21+
22+
23+
class Tickers(BaseModel):
24+
tickers: list = Field(title="All available stock tickers")
25+
26+
27+
class Stock(BaseModel):
28+
ticker: str = Field(..., title="Ticker of the stock")
29+
price: float = Field(..., title="Latest price of the stock")
30+
volatility: float = Field(..., title="Latest volatility of the stock price")
31+
32+
33+
class Price(BaseModel):
34+
date: date
35+
high: float = Field(..., title="High price for this date")
36+
low: float = Field(..., title="Low price for this date")
37+
close: float = Field(..., title="Closing price for this date")
38+
volume: int = Field(..., title="Daily volume for this date")
39+
adjusted: float = Field(..., title="Split-adjusted price for this date")
40+
41+
42+
app = FastAPI(
43+
title="Stocks API",
44+
description="The Stocks API provides pricing and volatility data for a "
45+
"limited number of US equities from 2010-2018",
46+
)
47+
48+
49+
@app.get("/stocks", response_model=Tickers)
50+
async def tickers():
51+
tickers = prices["ticker"].unique().tolist()
52+
return {"tickers": tickers}
53+
54+
55+
@app.get("/stocks/{ticker}", response_model=Stock)
56+
async def ticker(ticker: str):
57+
validate_ticker(ticker)
58+
59+
latest = prices.last_valid_index()
60+
ticker_prices = prices[prices["ticker"] == ticker]
61+
current_price = ticker_prices["close"][latest:].iloc[0].round(2)
62+
current_volatility = np.log(
63+
ticker_prices["adjusted"] / ticker_prices["adjusted"].shift(1)
64+
).var()
65+
66+
return {
67+
"ticker": ticker,
68+
"price": current_price,
69+
"volatility": current_volatility,
70+
}
71+
72+
73+
@app.get("/stocks/{ticker}/history", response_model=List[Price])
74+
async def history(ticker: str):
75+
validate_ticker(ticker)
76+
77+
ticker_prices = prices[prices["ticker"] == ticker]
78+
ticker_prices.loc[:, "date"] = ticker_prices.index.to_numpy()
79+
return ticker_prices.to_dict("records")
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"version": 1,
3+
"locale": "en_US.UTF-8",
4+
"metadata": {
5+
"appmode": "python-fastapi",
6+
"entrypoint": "main"
7+
},
8+
"extension": {
9+
"name": "stock-api-fastapi",
10+
"title": "FastAPI Stock Pricing Service",
11+
"description": "APIs are a great way for software engineering teams to use your models without translating them into different languages",
12+
"homepage": "https://github.com/posit-dev/connect-extensions/tree/main/extensions/stock-api-fastapi",
13+
"tags": [],
14+
"minimumConnectVersion": "2025.04.0",
15+
"version": "1.0.0"
16+
},
17+
"environment": {
18+
"python": {
19+
"requires": ">=3.11, <4"
20+
}
21+
},
22+
"python": {
23+
"version": "3.11.7",
24+
"package_manager": {
25+
"name": "pip",
26+
"version": "24.2",
27+
"package_file": "requirements.txt"
28+
}
29+
},
30+
"files": {
31+
"requirements.txt": {
32+
"checksum": "9b9389b1c871e9fe179877c446861cd9"
33+
},
34+
"README.md": {
35+
"checksum": "a33766bf7a7ff5fe0b4c9fc5fe583468"
36+
},
37+
"main.py": {
38+
"checksum": "7618d24f4c382163cdd224930e9b24c1"
39+
},
40+
"prices.csv": {
41+
"checksum": "e0bc27e3dd358c360863807e09079985"
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)