From 372a060ab74a20e9f48af0b00d325179d7861fda Mon Sep 17 00:00:00 2001 From: brayn003 Date: Wed, 3 Apr 2024 16:10:08 +0530 Subject: [PATCH 1/2] fix: adding tick model --- server/app/errors.py | 0 server/app/helpers/kite.py | 7 +++-- server/app/helpers/types.py | 5 ++++ server/app/main.py | 3 ++- server/app/models/tick.py | 45 ++++++++++++++++++-------------- server/app/routes/tick_routes.py | 16 ++++++++++++ 6 files changed, 52 insertions(+), 24 deletions(-) delete mode 100644 server/app/errors.py create mode 100644 server/app/helpers/types.py create mode 100644 server/app/routes/tick_routes.py diff --git a/server/app/errors.py b/server/app/errors.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/app/helpers/kite.py b/server/app/helpers/kite.py index f28304d..8ab935d 100644 --- a/server/app/helpers/kite.py +++ b/server/app/helpers/kite.py @@ -1,17 +1,16 @@ from datetime import datetime, timezone -from typing import Annotated, Dict, List, Literal, Optional +from typing import Dict, List, Literal, Optional from urllib.parse import parse_qs from uuid import uuid4 import pyotp from kiteconnect import KiteConnect from playwright.async_api import async_playwright, expect -from pydantic import BaseModel, BeforeValidator, EmailStr, Field, HttpUrl +from pydantic import BaseModel, EmailStr, Field, HttpUrl +from app.helpers.types import PyObjectId from app.services.cache import cache -PyObjectId = Annotated[str, BeforeValidator(str)] - class KiteConfiguration(BaseModel): integration_type: Literal["kite"] = "kite" diff --git a/server/app/helpers/types.py b/server/app/helpers/types.py new file mode 100644 index 0000000..f162a52 --- /dev/null +++ b/server/app/helpers/types.py @@ -0,0 +1,5 @@ +from typing import Annotated + +from pydantic import BeforeValidator + +PyObjectId = Annotated[str, BeforeValidator(str)] diff --git a/server/app/main.py b/server/app/main.py index 97cf88f..2ed1416 100644 --- a/server/app/main.py +++ b/server/app/main.py @@ -3,7 +3,7 @@ from starlette.middleware.sessions import SessionMiddleware from app.middlewares.auth_session import AuthSessionMiddleware -from app.routes import auth_routes, integration_routes, session_routes +from app.routes import auth_routes, integration_routes, session_routes, tick_routes from app.services.env import SESSION_SECRET # @asynccontextmanager @@ -33,6 +33,7 @@ app.include_router(auth_routes.router) app.include_router(session_routes.router) app.include_router(integration_routes.router) +app.include_router(tick_routes.router) @app.get("/") diff --git a/server/app/models/tick.py b/server/app/models/tick.py index 1709797..07dde6d 100644 --- a/server/app/models/tick.py +++ b/server/app/models/tick.py @@ -1,28 +1,31 @@ from datetime import datetime -from typing import List, Literal +from typing import List, Literal, Optional -from pydantic import BaseModel +from pydantic import BaseModel, Field, TypeAdapter +from app.helpers.types import PyObjectId +from app.services.db import db -class TickDepthLevel(BaseModel): + +class KiteTickDepthLevel(BaseModel): quantity: int price: float orders: int -class TickDepth(BaseModel): - buy: List[TickDepthLevel] - sell: List[TickDepthLevel] +class KiteTickDepth(BaseModel): + buy: List[KiteTickDepthLevel] + sell: List[KiteTickDepthLevel] -class TickOhlc(BaseModel): +class KiteTickOhlc(BaseModel): open: float high: float low: float close: float -class Tick(BaseModel): +class KiteTick(BaseModel): tradable: bool mode: Literal["full", "ltp", "quote"] instrument_token: int @@ -38,22 +41,26 @@ class Tick(BaseModel): oi_day_high: int oi_day_low: int exchange_timestamp: datetime - depth: TickDepth - - -class TicksMessage(BaseModel): - vendor: Literal["kite"] - ticks: List[Tick] + depth: KiteTickDepth -class TickDocMetadata(BaseModel): +class TickMetadata(BaseModel): instrument_token: int tradingsymbol: str -class TickDoc(BaseModel): - _id: str +class Tick(BaseModel): + id: Optional[PyObjectId] = Field(alias="_id", default=None) timestamp: datetime - metadata: TickDocMetadata - data: Tick + metadata: TickMetadata + data: KiteTick received_at: datetime + + +class TickManager: + @staticmethod + def list_ticks(tradingsymbol: str, from_date: datetime = None, to_date: datetime = None): + ticks = db.ticks.find({"metadata.tradingsymbol": tradingsymbol}).limit(100) + ticks = TypeAdapter(List[Tick]).validate_python(ticks) + + return ticks diff --git a/server/app/routes/tick_routes.py b/server/app/routes/tick_routes.py new file mode 100644 index 0000000..b542831 --- /dev/null +++ b/server/app/routes/tick_routes.py @@ -0,0 +1,16 @@ +from fastapi import APIRouter +from pydantic import BaseModel + +from app.models.tick import Tick, TickManager + +router = APIRouter(prefix="/api") + + +class ListTickseResponse(BaseModel): + ticks: list[Tick] + + +@router.get("/ticks/{tradingsymbol}", response_model=ListTickseResponse) +def list_ticks(tradingsymbol: str): + ticks = TickManager.list_ticks(tradingsymbol=tradingsymbol) + return {"ticks": ticks} From 790ae81e6ed320774c2a0b772a8f587795a54246 Mon Sep 17 00:00:00 2001 From: brayn003 Date: Fri, 5 Apr 2024 00:25:05 +0530 Subject: [PATCH 2/2] fix: wip charts --- .../dashboard/_components/market-feed.tsx | 94 ++++ .../dashboard/_components/overview.tsx | 112 ++++ client/app/private/dashboard/page.tsx | 123 +---- client/components/line-plot.tsx | 27 + client/package.json | 3 + client/pnpm-lock.yaml | 485 ++++++++++++++++++ server/app/models/tick.py | 12 +- 7 files changed, 741 insertions(+), 115 deletions(-) create mode 100644 client/app/private/dashboard/_components/market-feed.tsx create mode 100644 client/app/private/dashboard/_components/overview.tsx create mode 100644 client/components/line-plot.tsx diff --git a/client/app/private/dashboard/_components/market-feed.tsx b/client/app/private/dashboard/_components/market-feed.tsx new file mode 100644 index 0000000..0777a6a --- /dev/null +++ b/client/app/private/dashboard/_components/market-feed.tsx @@ -0,0 +1,94 @@ +"use client"; + +import type { IChartApi, UTCTimestamp } from "lightweight-charts"; +import { createChart } from "lightweight-charts"; +import { useEffect, useRef } from "react"; +import useSWRImmutable from "swr/immutable"; + +interface KiteTick { + tradable: boolean; + mode: "full" | "ltp" | "quote"; + instrument_token: number; + last_price: number; + last_traded_quantity: number; + average_traded_price: number; + volume_traded: number; + total_buy_quantity: number; + total_sell_quantity: number; + ohlc: { open: number; high: number; low: number; close: number }; + change: number; + last_trade_time: string; // date; + oi: number; + oi_day_high: number; + oi_day_low: number; + exchange_timestamp: string; // date; + depth: { + buy: Array<{ quantity: number; price: number; order: number }>; + sell: Array<{ quantity: number; price: number; order: number }>; + }; +} + +interface Tick { + id: string; + timestamp: string; // date; + metadata: { + instrument_token: string; + tradingsymbol: string; + }; + data: KiteTick; + received_at: string; // date; +} + +interface APITickResponse { + ticks: Tick[]; +} + +export function MarketFeed() { + const { data, isLoading } = useSWRImmutable("/api/ticks/HDFCBANK", async (url) => { + const res = await fetch(url); + return (await res.json()) as APITickResponse; + }); + const containerRef = useRef(null); + const chartRef = useRef(null); + + useEffect(() => { + if (!containerRef.current || !data) return; + chartRef.current = createChart(containerRef.current, { + width: containerRef.current.clientWidth, + height: 300, + timeScale: { + timeVisible: true, + }, + }); + chartRef.current.timeScale().fitContent(); + + const newSeries = chartRef.current.addLineSeries(); + const chartData = data.ticks.map<{ time: UTCTimestamp; value: number }>((tick) => ({ + time: (new Date(tick.received_at).getTime() / 1000) as UTCTimestamp, + value: tick.data.last_price, + })); + newSeries.setData(chartData); + + return () => { + if (chartRef.current) { + chartRef.current.remove(); + } + }; + }, [data]); + + useEffect(() => { + const handleResize = () => { + if (chartRef.current && containerRef.current) { + chartRef.current.applyOptions({ width: containerRef.current.clientWidth }); + } + }; + window.addEventListener("resize", handleResize); + return () => { + window.removeEventListener("resize", handleResize); + }; + }); + + // const { data, loading } = useQuery(GET_MARKET_FEED); + console.log({ isLoading, data }); + return
; +} diff --git a/client/app/private/dashboard/_components/overview.tsx b/client/app/private/dashboard/_components/overview.tsx new file mode 100644 index 0000000..6b63094 --- /dev/null +++ b/client/app/private/dashboard/_components/overview.tsx @@ -0,0 +1,112 @@ +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; + +export function Overview() { + return ( +
+
+ + + Total Revenue + + + + + +
$45,231.89
+

+20.1% from last month

+
+
+ + + Subscriptions + + + + + + + +
+2350
+

+180.1% from last month

+
+
+ + + Sales + + + + + + +
+12,234
+

+19% from last month

+
+
+ + + Active Now + + + + + +
+573
+

+201 since last hour

+
+
+
+
+ + + Overview + + + + + + Recent Sales + You made 265 sales this month. + + + +
+
+ ); +} diff --git a/client/app/private/dashboard/page.tsx b/client/app/private/dashboard/page.tsx index 44af2e0..ce4ad4a 100644 --- a/client/app/private/dashboard/page.tsx +++ b/client/app/private/dashboard/page.tsx @@ -4,6 +4,9 @@ import { PageHeader } from "@/components/page-header"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { MarketFeed } from "./_components/market-feed"; +import { Overview } from "./_components/overview"; + export const metadata: Metadata = { title: "Dashboard", description: "Example dashboard app built using the components.", @@ -16,121 +19,13 @@ export default function DashboardPage() { Overview - - Analytics - - - Reports - - - Notifications - + Market Feed - -
- - - Total Revenue - - - - - -
$45,231.89
-

+20.1% from last month

-
-
- - - Subscriptions - - - - - - - -
+2350
-

+180.1% from last month

-
-
- - - Sales - - - - - - -
+12,234
-

+19% from last month

-
-
- - - Active Now - - - - - -
+573
-

+201 since last hour

-
-
-
-
- - - Overview - - - - - - Recent Sales - You made 265 sales this month. - - - -
+ + + + +
diff --git a/client/components/line-plot.tsx b/client/components/line-plot.tsx new file mode 100644 index 0000000..20097c4 --- /dev/null +++ b/client/components/line-plot.tsx @@ -0,0 +1,27 @@ +import * as d3 from "d3"; + +interface LinePlotProps { + data: number[]; +} + +export default function LinePlot({ data = [] }: LinePlotProps) { + const width = 640; + const height = 400; + const marginTop = 20; + const marginRight = 20; + const marginBottom = 20; + const marginLeft = 20; + const x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]); + const y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]); + const line = d3.line((d, i) => x(i), y); + return ( + + + + {data.map((d, i) => ( + + ))} + + + ); +} diff --git a/client/package.json b/client/package.json index ec2c00c..cb388ec 100644 --- a/client/package.json +++ b/client/package.json @@ -26,6 +26,8 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "cmdk": "^0.2.1", + "d3": "^7.9.0", + "lightweight-charts": "^4.1.3", "lucide-react": "^0.350.0", "next": "14.1.1", "next-themes": "^0.3.0", @@ -38,6 +40,7 @@ "zod": "^3.22.4" }, "devDependencies": { + "@types/d3": "^7.4.3", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 5f77499..7692e36 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -56,6 +56,12 @@ dependencies: cmdk: specifier: ^0.2.1 version: 0.2.1(@types/react@18.2.61)(react-dom@18.2.0)(react@18.2.0) + d3: + specifier: ^7.9.0 + version: 7.9.0 + lightweight-charts: + specifier: ^4.1.3 + version: 4.1.3 lucide-react: specifier: ^0.350.0 version: 0.350.0(react@18.2.0) @@ -88,6 +94,9 @@ dependencies: version: 3.22.4 devDependencies: + '@types/d3': + specifier: ^7.4.3 + version: 7.4.3 '@types/node': specifier: ^20 version: 20.11.24 @@ -1390,6 +1399,189 @@ packages: tslib: 2.6.2 dev: false + /@types/d3-array@3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: true + + /@types/d3-axis@3.0.6: + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + dependencies: + '@types/d3-selection': 3.0.10 + dev: true + + /@types/d3-brush@3.0.6: + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + dependencies: + '@types/d3-selection': 3.0.10 + dev: true + + /@types/d3-chord@3.0.6: + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + dev: true + + /@types/d3-color@3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: true + + /@types/d3-contour@3.0.6: + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.14 + dev: true + + /@types/d3-delaunay@6.0.4: + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + dev: true + + /@types/d3-dispatch@3.0.6: + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + dev: true + + /@types/d3-drag@3.0.7: + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + dependencies: + '@types/d3-selection': 3.0.10 + dev: true + + /@types/d3-dsv@3.0.7: + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + dev: true + + /@types/d3-ease@3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: true + + /@types/d3-fetch@3.0.7: + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + dependencies: + '@types/d3-dsv': 3.0.7 + dev: true + + /@types/d3-force@3.0.9: + resolution: {integrity: sha512-IKtvyFdb4Q0LWna6ymywQsEYjK/94SGhPrMfEr1TIc5OBeziTi+1jcCvttts8e0UWZIxpasjnQk9MNk/3iS+kA==} + dev: true + + /@types/d3-format@3.0.4: + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + dev: true + + /@types/d3-geo@3.1.0: + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + dependencies: + '@types/geojson': 7946.0.14 + dev: true + + /@types/d3-hierarchy@3.1.7: + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + dev: true + + /@types/d3-interpolate@3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: true + + /@types/d3-path@3.1.0: + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + dev: true + + /@types/d3-polygon@3.0.2: + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + dev: true + + /@types/d3-quadtree@3.0.6: + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + dev: true + + /@types/d3-random@3.0.3: + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + dev: true + + /@types/d3-scale-chromatic@3.0.3: + resolution: {integrity: sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==} + dev: true + + /@types/d3-scale@4.0.8: + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + dependencies: + '@types/d3-time': 3.0.3 + dev: true + + /@types/d3-selection@3.0.10: + resolution: {integrity: sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==} + dev: true + + /@types/d3-shape@3.1.6: + resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + dependencies: + '@types/d3-path': 3.1.0 + dev: true + + /@types/d3-time-format@4.0.3: + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + dev: true + + /@types/d3-time@3.0.3: + resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} + dev: true + + /@types/d3-timer@3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: true + + /@types/d3-transition@3.0.8: + resolution: {integrity: sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==} + dependencies: + '@types/d3-selection': 3.0.10 + dev: true + + /@types/d3-zoom@3.0.8: + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.10 + dev: true + + /@types/d3@7.4.3: + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.9 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.0 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.8 + '@types/d3-scale-chromatic': 3.0.3 + '@types/d3-selection': 3.0.10 + '@types/d3-shape': 3.1.6 + '@types/d3-time': 3.0.3 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.8 + '@types/d3-zoom': 3.0.8 + dev: true + + /@types/geojson@7946.0.14: + resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} + dev: true + /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true @@ -2017,6 +2209,11 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + /commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true @@ -2037,6 +2234,254 @@ packages: /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + /d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + dependencies: + internmap: 2.0.3 + dev: false + + /d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + dev: false + + /d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dev: false + + /d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + dev: false + + /d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + dependencies: + delaunator: 5.0.1 + dev: false + + /d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + dev: false + + /d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + dev: false + + /d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + dev: false + + /d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + dev: false + + /d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + dependencies: + d3-dsv: 3.0.1 + dev: false + + /d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + dev: false + + /d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + dev: false + + /d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + dev: false + + /d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false + + /d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + dev: false + + /d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + dev: false + + /d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + dev: false + + /d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + dev: false + + /d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + dev: false + + /d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + dev: false + + /d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + dev: false + + /d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + dependencies: + d3-time: 3.1.0 + dev: false + + /d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + dev: false + + /d3-transition@3.0.1(d3-selection@3.0.0): + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + dev: false + + /d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dev: false + + /d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + dev: false + /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true @@ -2086,6 +2531,12 @@ packages: object-keys: 1.1.1 dev: true + /delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + dependencies: + robust-predicates: 3.0.2 + dev: false + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2732,6 +3183,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /fancy-canvas@2.1.0: + resolution: {integrity: sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ==} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -3003,6 +3458,13 @@ packages: dependencies: function-bind: 1.1.2 + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -3041,6 +3503,11 @@ packages: side-channel: 1.0.6 dev: true + /internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + dev: false + /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -3308,6 +3775,12 @@ packages: type-check: 0.4.0 dev: true + /lightweight-charts@4.1.3: + resolution: {integrity: sha512-SJacmEyx3LmT2Qsc7Kq7cEX7nEHtQv0MOlujhRlcDxhW62pG6nkBlcM52/jNqkq8B28KQeVmgOQ7zrdJ4BCPDw==} + dependencies: + fancy-canvas: 2.1.0 + dev: false + /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -3928,11 +4401,19 @@ packages: glob: 7.2.3 dev: true + /robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + dev: false + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 + /rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + dev: false + /safe-array-concat@1.1.0: resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} engines: {node: '>=0.4'} @@ -3952,6 +4433,10 @@ packages: is-regex: 1.1.4 dev: true + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: diff --git a/server/app/models/tick.py b/server/app/models/tick.py index 07dde6d..385a729 100644 --- a/server/app/models/tick.py +++ b/server/app/models/tick.py @@ -35,6 +35,7 @@ class KiteTick(BaseModel): volume_traded: int total_buy_quantity: int total_sell_quantity: int + ohlc: KiteTickOhlc change: float last_trade_time: datetime oi: int @@ -60,7 +61,16 @@ class Tick(BaseModel): class TickManager: @staticmethod def list_ticks(tradingsymbol: str, from_date: datetime = None, to_date: datetime = None): - ticks = db.ticks.find({"metadata.tradingsymbol": tradingsymbol}).limit(100) + ticks = ( + db.ticks.find( + { + "received_at": {"$gte": datetime(2021, 1, 1)}, + "metadata.tradingsymbol": tradingsymbol, + } + ) + .sort("received_at", 1) + .limit(5000) + ) ticks = TypeAdapter(List[Tick]).validate_python(ticks) return ticks