openapi: 3.1.0 info: title: Invest Copilot API description: AI-native investment research and portfolio copilot version: 0.1.0 contact: name: Invest Copilot Team email: dev@invest-copilot.local servers: - url: http://localhost:3000/api/v1 description: Development server - url: https://api.invest-copilot.local/api/v1 description: Production server tags: - name: stocks description: Stock search, profiles, and data - name: watchlists description: Watchlist management - name: strategies description: Strategy creation and management - name: screeners description: Stock screeners - name: sectors description: Sector rotation analysis - name: alerts description: Real-time alerts and notifications - name: streaming description: Server-Sent Events for real-time updates paths: # ─── Stock Search & Profile ────────────────────────────── /search: get: tags: [stocks] summary: Search stocks by ticker or name operationId: searchStocks parameters: - name: q in: query required: true description: Search query (ticker or company name) schema: type: string minLength: 1 maxLength: 50 - name: limit in: query schema: type: integer minimum: 1 maximum: 50 default: 10 responses: 200: description: Search results content: application/json: schema: type: array items: $ref: '#/components/schemas/SearchResult' 400: description: Invalid search query /stocks/{ticker}: get: tags: [stocks] summary: Get full stock profile with all data operationId: getStockProfile parameters: - name: ticker in: path required: true schema: type: string example: AAPL responses: 200: description: Complete stock profile content: application/json: schema: $ref: '#/components/schemas/StockProfileResponse' 404: description: Stock not found /stocks/{ticker}/peers: get: tags: [stocks] summary: Get peer group with relative performance operationId: getStockPeers parameters: - name: ticker in: path required: true schema: type: string example: AAPL responses: 200: description: Peer group data content: application/json: schema: $ref: '#/components/schemas/PeerGroupResponse' /stocks/{ticker}/price/history: get: tags: [stocks] summary: Get historical price data operationId: getPriceHistory parameters: - name: ticker in: path required: true schema: type: string example: AAPL - name: interval in: query schema: type: string enum: [1m, 5m, 15m, 30m, 1h, 1d, 1w, 1M] default: 1d - name: start in: query required: true schema: type: string format: date-time example: "2024-01-01T00:00:00Z" - name: end in: query required: true schema: type: string format: date-time example: "2024-12-31T23:59:59Z" responses: 200: description: Price history content: application/json: schema: type: array items: $ref: '#/components/schemas/PriceEvent' /stocks/{ticker}/sec-filings: get: tags: [stocks] summary: Get SEC filings with analysis operationId: getSecFilings parameters: - name: ticker in: path required: true schema: type: string example: AAPL - name: form_type in: query description: Filter by form type schema: type: string enum: [10-K, 10-Q, 8-K, 4, 13F, 13D, 13G] - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 responses: 200: description: SEC filings content: application/json: schema: type: array items: $ref: '#/components/schemas/SecFiling' /stocks/{ticker}/insider-trades: get: tags: [stocks] summary: Get insider trading activity operationId: getInsiderTrades parameters: - name: ticker in: path required: true schema: type: string example: AAPL - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 responses: 200: description: Insider trades content: application/json: schema: type: array items: $ref: '#/components/schemas/InsiderTrade' /stocks/{ticker}/sentiment: get: tags: [stocks] summary: Get sentiment signals from all sources operationId: getStockSentiment parameters: - name: ticker in: path required: true schema: type: string example: AAPL responses: 200: description: Sentiment signals content: application/json: schema: $ref: '#/components/schemas/SentimentResponse' # ─── Watchlists ───────────────────────────────────────── /watchlists: get: tags: [watchlists] summary: Get all user watchlists operationId: getUserWatchlists responses: 200: description: List of watchlists content: application/json: schema: type: array items: $ref: '#/components/schemas/Watchlist' post: tags: [watchlists] summary: Create a new watchlist operationId: createWatchlist requestBody: required: true content: application/json: schema: type: object required: [name] properties: name: type: string minLength: 1 maxLength: 255 description: type: string maxLength: 1000 responses: 201: description: Watchlist created content: application/json: schema: $ref: '#/components/schemas/Watchlist' /watchlists/{id}: get: tags: [watchlists] summary: Get watchlist with items and live prices operationId: getWatchlist parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Watchlist with items content: application/json: schema: $ref: '#/components/schemas/WatchlistWithPrices' put: tags: [watchlists] summary: Update watchlist operationId: updateWatchlist parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: name: type: string description: type: string responses: 200: description: Watchlist updated delete: tags: [watchlists] summary: Delete watchlist operationId: deleteWatchlist parameters: - name: id in: path required: true schema: type: string format: uuid responses: 204: description: Watchlist deleted /watchlists/{id}/items: get: tags: [watchlists] summary: Get watchlist items operationId: getWatchlistItems parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Watchlist items content: application/json: schema: type: array items: $ref: '#/components/schemas/WatchlistItem' post: tags: [watchlists] summary: Add ticker to watchlist operationId: addWatchlistItem parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: [ticker] properties: ticker: type: string maxLength: 20 type: type: string enum: [stock, etf, index] notes: type: string maxLength: 500 responses: 201: description: Item added delete: tags: [watchlists] summary: Remove ticker from watchlist operationId: removeWatchlistItem parameters: - name: id in: path required: true schema: type: string format: uuid - name: ticker in: query required: true schema: type: string responses: 204: description: Item removed # ─── Strategies ───────────────────────────────────────── /strategies: get: tags: [strategies] summary: Get all user strategies operationId: getUserStrategies responses: 200: description: List of strategies content: application/json: schema: type: array items: $ref: '#/components/schemas/Strategy' post: tags: [strategies] summary: Create a new strategy operationId: createStrategy requestBody: required: true content: application/json: schema: type: object required: [name, type, conditions] properties: name: type: string minLength: 1 maxLength: 255 description: type: string maxLength: 1000 type: type: string enum: [technical, fundamental, hybrid] conditions: type: object required: [rules, logic] properties: rules: type: array items: type: object required: [indicator, operator, value] properties: indicator: type: string operator: type: string enum: [lt, gt, lte, gte, eq, neq, crossover, crossbelow] value: type: number period: type: integer source: type: string description: type: string logic: type: string enum: [AND, OR] timeframe: type: string responses: 201: description: Strategy created /strategies/{id}: get: tags: [strategies] summary: Get strategy details operationId: getStrategy parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Strategy details put: tags: [strategies] summary: Update strategy operationId: updateStrategy parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: name: type: string description: type: string conditions: type: object responses: 200: description: Strategy updated delete: tags: [strategies] summary: Delete strategy operationId: deleteStrategy parameters: - name: id in: path required: true schema: type: string format: uuid responses: 204: description: Strategy deleted /strategies/{id}/backtest: post: tags: [strategies] summary: Run backtest on a strategy operationId: backtestStrategy parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: start_date: type: string format: date end_date: type: string format: date watchlist_id: type: string format: uuid responses: 200: description: Backtest results content: application/json: schema: $ref: '#/components/schemas/BacktestResult' # ─── Screeners ────────────────────────────────────────── /screeners: get: tags: [screeners] summary: Get user screeners operationId: getUserScreeners responses: 200: description: List of screeners post: tags: [screeners] summary: Create a new screener operationId: createScreener requestBody: required: true content: application/json: schema: type: object required: [name, conditions] properties: name: type: string description: type: string conditions: type: array items: type: object required: [field, operator, value] properties: field: type: string operator: type: string enum: [lt, gt, lte, gte, eq, neq] value: type: number responses: 201: description: Screener created /screeners/{id}/run: post: tags: [screeners] summary: Execute a screener operationId: runScreener parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Screener results content: application/json: schema: type: object properties: results: type: array items: $ref: '#/components/schemas/ScreenerResult' total: type: integer runAt: type: string format: date-time /screeners/{id}/results: get: tags: [screeners] summary: Get last screener results operationId: getScreenerResults parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Screener results # ─── Sector Rotation ──────────────────────────────────── /sectors/rotation: get: tags: [sectors] summary: Get current sector rotation analysis operationId: getSectorRotation responses: 200: description: Current rotation analysis content: application/json: schema: $ref: '#/components/schemas/SectorRotationResponse' post: tags: [sectors] summary: Trigger manual rotation scan operationId: triggerRotationScan responses: 200: description: Scan completed content: application/json: schema: $ref: '#/components/schemas/SectorRotationResponse' /sectors/rotation/history: get: tags: [sectors] summary: Get historical rotation data operationId: getRotationHistory parameters: - name: from in: query required: true schema: type: string format: date - name: to in: query schema: type: string format: date - name: sector in: query schema: type: string example: XLK responses: 200: description: Historical rotations # ─── Alerts ───────────────────────────────────────────── /alerts: get: tags: [alerts] summary: Get user alerts operationId: getUserAlerts parameters: - name: status in: query description: Filter by status schema: type: string enum: [active, resolved, dismissed] default: active - name: limit in: query schema: type: integer default: 50 maximum: 200 responses: 200: description: List of alerts content: application/json: schema: type: array items: $ref: '#/components/schemas/Alert' delete: tags: [alerts] summary: Clear resolved alerts operationId: clearResolvedAlerts responses: 204: description: Alerts cleared /alerts/{id}/resolve: post: tags: [alerts] summary: Mark alert as resolved operationId: resolveAlert parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Alert resolved /alerts/{id}/dismiss: post: tags: [alerts] summary: Dismiss an alert operationId: dismissAlert parameters: - name: id in: path required: true schema: type: string format: uuid responses: 200: description: Alert dismissed # ─── Streaming (SSE) ─────────────────────────────────── /stream/alerts: get: tags: [streaming] summary: Server-Sent Events stream for real-time alerts operationId: getAlertStream responses: 200: description: SSE stream content: text/event-stream: schema: type: string example: | event: alert data: {"id":"abc","message":"RSI oversold on AAPL","ticker":"AAPL"} event: rotation data: {"sector":"XLK","signal":"in","rankChange":3} components: schemas: # ─── Stock Data ─────────────────────────────────────── SearchResult: type: object properties: ticker: type: string name: type: string exchange: type: string sector: type: string marketCap: type: number PriceEvent: type: object properties: date: type: string format: date-time open: type: number high: type: number low: type: number close: type: number volume: type: integer adjustedClose: type: number StockProfileResponse: type: object properties: profile: $ref: '#/components/schemas/StockProfile' price: $ref: '#/components/schemas/PriceEvent' peers: type: array items: $ref: '#/components/schemas/Peer' sentiment: $ref: '#/components/schemas/SentimentResponse' secFilings: type: array items: $ref: '#/components/schemas/SecFiling' insiderTrades: type: array items: $ref: '#/components/schemas/InsiderTrade' StockProfile: type: object properties: ticker: type: string name: type: string exchange: type: string sector: type: string industry: type: string marketCap: type: number description: type: string website: type: string nullable: true ceo: type: string nullable: true employees: type: integer nullable: true peRatio: type: number nullable: true eps: type: number nullable: true dividendYield: type: number nullable: true beta: type: number nullable: true Peer: type: object properties: ticker: type: string name: type: string similarityScore: type: number relativeStrength: type: number priceChange1d: type: number priceChange5d: type: number priceChange30d: type: number PeerGroupResponse: type: object properties: ticker: type: string peers: type: array items: $ref: '#/components/schemas/Peer' benchmark: type: string benchmarkChange1d: type: number SecFiling: type: object properties: ticker: type: string cik: type: string formType: type: string filingDate: type: string format: date reportDate: type: string format: date accessionNumber: type: string url: type: string contentSummary: type: string sentimentScore: type: number tags: type: array items: type: string InsiderTrade: type: object properties: ticker: type: string insiderName: type: string insiderTitle: type: string transactionDate: type: string format: date transactionType: type: string enum: [BUY, SELL, GIFT, IN_EX] shares: type: integer pricePerShare: type: number totalValue: type: number sharesOwnedAfter: type: integer filingDate: type: string format: date SentimentResponse: type: object properties: ticker: type: string signals: type: array items: $ref: '#/components/schemas/SentimentSignal' averageScore: type: number confidence: type: number SentimentSignal: type: object properties: source: type: string score: type: number minimum: -1 maximum: 1 confidence: type: number timestamp: type: string format: date-time context: type: string # ─── Watchlists ─────────────────────────────────────── Watchlist: type: object properties: id: type: string format: uuid name: type: string description: type: string nullable: true isDefault: type: boolean itemCount: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time WatchlistWithPrices: allOf: - $ref: '#/components/schemas/Watchlist' - type: object properties: items: type: array items: $ref: '#/components/schemas/WatchlistItemWithPrice' WatchlistItem: type: object properties: ticker: type: string type: type: string enum: [stock, etf, index] notes: type: string nullable: true addedAt: type: string format: date-time priceAtAddition: type: number nullable: true WatchlistItemWithPrice: allOf: - $ref: '#/components/schemas/WatchlistItem' - type: object properties: currentPrice: type: number priceChange1d: type: number priceChangePercent: type: number marketCap: type: number nullable: true # ─── Strategies ─────────────────────────────────────── Strategy: type: object properties: id: type: string format: uuid name: type: string description: type: string type: type: string enum: [technical, fundamental, hybrid] conditions: type: object properties: rules: type: array items: type: object properties: indicator: type: string operator: type: string value: type: number period: type: integer source: type: string description: type: string logic: type: string enum: [AND, OR] timeframe: type: string backtestResults: $ref: '#/components/schemas/BacktestResult' nullable: true createdAt: type: string format: date-time updatedAt: type: string format: date-time BacktestResult: type: object properties: startDate: type: string format: date endDate: type: string format: date totalReturn: type: number annualizedReturn: type: number maxDrawdown: type: number sharpeRatio: type: number winRate: type: number totalTrades: type: integer avgHoldTime: type: string equityCurve: type: array items: type: number # ─── Screeners ──────────────────────────────────────── Screener: type: object properties: id: type: string format: uuid name: type: string description: type: string nullable: true lastRunAt: type: string format: date-time nullable: true resultsCount: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time ScreenerResult: type: object properties: ticker: type: string matchScore: type: number rankedPosition: type: integer resultData: type: object # ─── Sector Rotation ────────────────────────────────── SectorRotation: type: object properties: detectionDate: type: string format: date sectorTicker: type: string sectorName: type: string rankNow: type: integer rankPrevious: type: integer rankChange: type: integer momentum20d: type: number momentum50d: type: number momentum200d: type: number relativeStrength: type: number signal: type: string enum: [in, out, stable, accelerating] analysisSummary: type: string SectorRotationResponse: type: object properties: date: type: string format: date rotations: type: array items: $ref: '#/components/schemas/SectorRotation' inRotation: type: array items: type: string outOfRotation: type: array items: type: string macroContext: type: object nullable: true # ─── Alerts ─────────────────────────────────────────── Alert: type: object properties: id: type: string format: uuid watchlistId: type: string format: uuid strategyId: type: string format: uuid nullable: true ticker: type: string type: type: string enum: [strategy_trigger, sec_filing, sentiment, rotation, price] triggerType: type: string message: type: string severity: type: string enum: [info, warning, critical] status: type: string enum: [active, resolved, dismissed] triggeredAt: type: string format: date-time resolvedAt: type: string format: date-time nullable: true metadata: type: object