phase-6: typescript introduction

This commit is contained in:
Sai Kiran Vella
2026-06-04 22:16:48 -04:00
committed by saikiranvella
parent 57625c27d7
commit c160e65bd6
69 changed files with 2323 additions and 1036 deletions
-80
View File
@@ -1,80 +0,0 @@
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { randomUUID } from 'crypto';
const STORE_PATH = './market-calls.json';
// MarketCallStore — persists quarterly market thesis entries to market-calls.json.
//
// A market call captures:
// - A written thesis (the reasoning behind the call)
// - Tickers to watch
// - A snapshot of each ticker's price + signal at the time of the call
// - Performance tracking (current vs snapshot price) computed on read
//
// Format:
// {
// "calls": [
// {
// "id": "uuid",
// "title": "Q3 2025 — Rate pivot & tech rotation",
// "quarter": "Q3 2025",
// "date": "2025-07-01",
// "thesis": "The Fed is expected to begin cutting...",
// "tickers": ["AAPL", "MSFT", "TLT"],
// "snapshot": {
// "AAPL": { "price": 195.00, "signal": "✅ Strong Buy", "verdict": "BUY (High Conviction)" }
// },
// "createdAt": "2025-07-01T14:22:00.000Z"
// }
// ]
// }
export class MarketCallStore {
_load() {
if (!existsSync(STORE_PATH)) return { calls: [] };
try {
return JSON.parse(readFileSync(STORE_PATH, 'utf8'));
} catch {
return { calls: [] };
}
}
_save(data) {
writeFileSync(STORE_PATH, JSON.stringify(data, null, 2), 'utf8');
}
list() {
return this._load().calls.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
}
get(id) {
return this._load().calls.find((c) => c.id === id) ?? null;
}
// Create a new call. snapshot is an object keyed by ticker with { price, signal, verdict }.
create({ title, quarter, date, thesis, tickers, snapshot }) {
const data = this._load();
const call = {
id: randomUUID(),
title,
quarter,
date: date ?? new Date().toISOString().slice(0, 10),
thesis,
tickers,
snapshot: snapshot ?? {},
createdAt: new Date().toISOString(),
};
data.calls.push(call);
this._save(data);
return call;
}
delete(id) {
const data = this._load();
const before = data.calls.length;
data.calls = data.calls.filter((c) => c.id !== id);
if (data.calls.length === before) return false;
this._save(data);
return true;
}
}
+76
View File
@@ -0,0 +1,76 @@
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { randomUUID } from 'crypto';
import type { MarketCall, Signal, TickerSnapshot } from '../types.js';
const STORE_PATH = './market-calls.json';
interface StoreData {
calls: (MarketCall & { createdAt: string })[];
}
interface CreateCallInput {
title: string;
quarter: string;
date?: string;
thesis: string;
tickers: string[];
snapshot?: Record<string, TickerSnapshot>;
}
export class MarketCallStore {
private _load(): StoreData {
if (!existsSync(STORE_PATH)) return { calls: [] };
try {
return JSON.parse(readFileSync(STORE_PATH, 'utf8')) as StoreData;
} catch {
return { calls: [] };
}
}
private _save(data: StoreData): void {
writeFileSync(STORE_PATH, JSON.stringify(data, null, 2), 'utf8');
}
list(): (MarketCall & { createdAt: string })[] {
return this._load().calls.sort(
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
);
}
get(id: string): (MarketCall & { createdAt: string }) | null {
return this._load().calls.find((c) => c.id === id) ?? null;
}
create({
title,
quarter,
date,
thesis,
tickers,
snapshot,
}: CreateCallInput): MarketCall & { createdAt: string } {
const data = this._load();
const call = {
id: randomUUID(),
title,
quarter,
date: date ?? new Date().toISOString().slice(0, 10),
thesis,
tickers,
snapshot: snapshot ?? {},
createdAt: new Date().toISOString(),
};
data.calls.push(call);
this._save(data);
return call;
}
delete(id: string): boolean {
const data = this._load();
const before = data.calls.length;
data.calls = data.calls.filter((c) => c.id !== id);
if (data.calls.length === before) return false;
this._save(data);
return true;
}
}