Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/ingestor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"test:cov": "jest --coverage"
},
"dependencies": {
"@oracle-stocks/shared": "*",
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
Expand Down
3 changes: 2 additions & 1 deletion apps/ingestor/src/controllers/prices.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Controller, Get, Logger } from '@nestjs/common';
import { PriceFetcherService, RawPrice } from '../services/price-fetcher.service';
import { RawPrice } from '@oracle-stocks/shared';
import { PriceFetcherService } from '../services/price-fetcher.service';

@Controller('prices')
export class PricesController {
Expand Down
2 changes: 2 additions & 0 deletions apps/ingestor/src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { PriceProvider } from './provider.interface';
export { MockProvider } from './mock.provider';
19 changes: 19 additions & 0 deletions apps/ingestor/src/providers/mock.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RawPrice } from '@oracle-stocks/shared';
import { PriceProvider } from './provider.interface';

export class MockProvider implements PriceProvider {
readonly name = 'MockProvider';

async fetchPrices(symbols: string[]): Promise<RawPrice[]> {
return symbols.map(symbol => ({
symbol,
price: this.generateMockPrice(),
timestamp: Date.now(),
source: this.name,
}));
}

private generateMockPrice(): number {
return parseFloat((Math.random() * 1000 + 50).toFixed(2));
}
}
6 changes: 6 additions & 0 deletions apps/ingestor/src/providers/provider.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { RawPrice } from '@oracle-stocks/shared';

export interface PriceProvider {
readonly name: string;
fetchPrices(symbols: string[]): Promise<RawPrice[]>;
}
32 changes: 11 additions & 21 deletions apps/ingestor/src/services/price-fetcher.service.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import { Injectable, Logger } from '@nestjs/common';

export interface RawPrice {
symbol: string;
price: number;
timestamp: number;
source: string;
}
import { RawPrice } from '@oracle-stocks/shared';
import { PriceProvider, MockProvider } from '../providers';

@Injectable()
export class PriceFetcherService {
private readonly logger = new Logger(PriceFetcherService.name);
private rawPrices: RawPrice[] = [];
private readonly providers: PriceProvider[] = [];

constructor() {
this.providers.push(new MockProvider());
}

async fetchRawPrices(): Promise<RawPrice[]> {
const symbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA'];
const sources = ['AlphaVantage', 'YahooFinance', 'Finnhub'];

this.rawPrices = symbols.flatMap(symbol =>
sources.map(source => ({
symbol,
price: this.generateMockPrice(),
timestamp: Date.now(),
source,
}))
);
const pricePromises = this.providers.map(provider => provider.fetchPrices(symbols));
const results = await Promise.all(pricePromises);
this.rawPrices = results.flat();

this.logger.log(`Fetched ${this.rawPrices.length} raw prices from external APIs`);
this.logger.log(`Fetched ${this.rawPrices.length} raw prices from ${this.providers.length} provider(s)`);
this.rawPrices.forEach(price => {
this.logger.debug(
`${price.source} - ${price.symbol}: $${price.price.toFixed(2)} at ${new Date(price.timestamp).toISOString()}`
Expand All @@ -38,8 +32,4 @@ export class PriceFetcherService {
getRawPrices(): RawPrice[] {
return this.rawPrices;
}

private generateMockPrice(): number {
return parseFloat((Math.random() * 1000 + 50).toFixed(2));
}
}
19 changes: 1 addition & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/shared/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Main entry point for the Shared package

// Shared utilities and types will be exported here
// Type exports
export * from './types';
1 change: 1 addition & 0 deletions packages/shared/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RawPrice } from './raw-price';
17 changes: 17 additions & 0 deletions packages/shared/src/types/raw-price.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Normalized price data from any provider
* This is the canonical format for all ingested price data
*/
export interface RawPrice {
/** Stock ticker symbol (e.g., 'AAPL', 'GOOGL') */
symbol: string;

/** Price value in USD */
price: number;

/** Unix timestamp in milliseconds when price was recorded */
timestamp: number;

/** Data source identifier (e.g., 'AlphaVantage', 'YahooFinance') */
source: string;
}