refactor: wire web to the in-repo engine and shared data dir
- web/src/server/paths.ts resolves the repo root from its own location, loads the single repo-root .env, and defines data/web/ (watchlist, stock cache, backtest cache) and data/precomputed/. - The API spawns bridge.py at the repo root instead of ../quant. - precompute_backtest.py writes to data/precomputed/ instead of ../stock-agent/data/precomputed. - Rename the project to quant-trading (web package quant-trading-web). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1 +0,0 @@
|
||||
IPADS_API_KEY=
|
||||
4
web/package-lock.json
generated
4
web/package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "personal-stock-agent",
|
||||
"name": "quant-trading-web",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "personal-stock-agent",
|
||||
"name": "quant-trading-web",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "personal-stock-agent",
|
||||
"name": "quant-trading-web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "dotenv/config";
|
||||
import { PRECOMPUTED_DIR, WEB_DATA_DIR } from "./paths";
|
||||
import cors from "cors";
|
||||
import express from "express";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
@@ -15,11 +15,10 @@ import { listStrategies, runBacktest, getCachedResult, getLiveStrategies } from
|
||||
|
||||
const port = Number(process.env.PORT ?? 8787);
|
||||
const host = process.env.HOST ?? "127.0.0.1";
|
||||
const dataDir = process.env.STOCK_AGENT_DATA_DIR ?? join(process.cwd(), "data");
|
||||
|
||||
const watchlistStore = new WatchlistStore(join(dataDir, "watchlist.json"));
|
||||
const watchlistStore = new WatchlistStore(join(WEB_DATA_DIR, "watchlist.json"));
|
||||
const dataProvider = createProvider(loadIpadsConfig().apiKey);
|
||||
const stockDataCache = new StockDataCache(join(dataDir, "cache"), dataProvider);
|
||||
const stockDataCache = new StockDataCache(join(WEB_DATA_DIR, "cache"), dataProvider);
|
||||
const app = express();
|
||||
|
||||
let cachedReportUpdatedAt = 0;
|
||||
@@ -157,7 +156,7 @@ app.get("/api/strategies", async (_request, response, next) => {
|
||||
});
|
||||
|
||||
function loadPrecomputedFile() {
|
||||
const precomputedPath = join(dataDir, "precomputed", "backtest_results.json");
|
||||
const precomputedPath = join(PRECOMPUTED_DIR, "backtest_results.json");
|
||||
if (!existsSync(precomputedPath)) {
|
||||
throw new Error("Pre-computed results not available. Run precompute_backtest.py first.");
|
||||
}
|
||||
|
||||
14
web/src/server/paths.ts
Normal file
14
web/src/server/paths.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { config } from "dotenv";
|
||||
import { join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
// web/src/server/ → repository root, which also holds bridge.py and the Python engine.
|
||||
export const REPO_ROOT = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
||||
|
||||
// Secrets such as IPADS_API_KEY live in the single untracked repo-root .env.
|
||||
config({ path: join(REPO_ROOT, ".env"), quiet: true });
|
||||
|
||||
// Web-only state: watchlist, per-stock cache and backtest result cache.
|
||||
export const WEB_DATA_DIR = join(REPO_ROOT, "data", "web");
|
||||
// Written by precompute_backtest.py, read by the strategy page.
|
||||
export const PRECOMPUTED_DIR = join(REPO_ROOT, "data", "precomputed");
|
||||
@@ -1,11 +1,11 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, unlinkSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { join } from "node:path";
|
||||
import { REPO_ROOT, WEB_DATA_DIR } from "./paths";
|
||||
import type { BacktestConfig, BacktestResult, LiveStrategyState, StrategyInfo } from "../shared/strategyTypes.js";
|
||||
|
||||
const QUANT_DIR = resolve(process.env.QUANT_PROJECT_DIR || join(process.cwd(), "../quant"));
|
||||
const CACHE_DIR = join(process.env.STOCK_AGENT_DATA_DIR || join(process.cwd(), "data"), "strategy_cache");
|
||||
const CACHE_DIR = join(WEB_DATA_DIR, "strategy_cache");
|
||||
const TIMEOUT_MS = Number(process.env.QUANT_BACKTEST_TIMEOUT_MS) || 180_000;
|
||||
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
||||
const MAX_CACHE_FILES = 50;
|
||||
@@ -37,7 +37,7 @@ function stableStringify(value: unknown): string {
|
||||
function runBridge(args: string[]): Promise<unknown> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn("uv", ["run", "python", "bridge.py", ...args], {
|
||||
cwd: QUANT_DIR,
|
||||
cwd: REPO_ROOT,
|
||||
env: { ...process.env, PYTHONUNBUFFERED: "1" },
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user