WIP: bootstrap and partial real Solana watcher implementation

This commit is contained in:
2026-08-16 09:17:45 +00:00
commit dc23412c3f
7232 changed files with 1687637 additions and 0 deletions

117
src/metrics/index.ts Normal file
View File

@@ -0,0 +1,117 @@
import { InfluxDB, Point, WriteApi } from '@influxdata/influxdb-client';
import { IMetricsProvider } from '../domain/interfaces.js';
import { logger } from '../logging/index.js';
export class InfluxMetricsProvider implements IMetricsProvider {
private writeApi: WriteApi | null = null;
private influx: InfluxDB | null = null;
constructor(url: string, token: string, org: string, bucket: string) {
try {
this.influx = new InfluxDB({ url, token });
this.writeApi = this.influx.getWriteApi(org, bucket, 'ms', {
writeFailed(error) {
logger.error('InfluxDB metrics point write failed', error);
},
});
logger.info('InfluxDB metrics provider initialized successfully');
} catch (error) {
logger.error(
'Failed to initialize InfluxDB metrics provider. System will run with degraded/no time-series metrics reporting.',
error,
);
}
}
private writePoint(point: Point): void {
if (!this.writeApi) {
logger.debug('InfluxDB write client not initialized, discarding point', {
measurement: point.toLineProtocol(),
});
return;
}
try {
this.writeApi.writePoint(point);
} catch (error) {
logger.error('Error writing point to InfluxDB', error);
}
}
recordWalletDetectionLatency(latencyMs: number, wallet: string): void {
const p = new Point('wallet_detection_latency')
.tag('wallet', wallet)
.floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordSignalProcessingLatency(latencyMs: number): void {
const p = new Point('signal_processing_latency').floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordQuoteLatency(latencyMs: number, provider: string): void {
const p = new Point('quote_latency').tag('provider', provider).floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordExecutionLatency(latencyMs: number, scenario: number): void {
const p = new Point('execution_latency')
.tag('scenario', `${scenario}ms`)
.floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordPrice(tokenMint: string, priceSol: number): void {
const p = new Point('token_price').tag('token_mint', tokenMint).floatField('price_sol', priceSol);
this.writePoint(p);
}
recordPortfolioBalance(balanceSol: number, scenario: number): void {
const p = new Point('portfolio_balance')
.tag('scenario', `${scenario}ms`)
.floatField('balance_sol', balanceSol);
this.writePoint(p);
}
recordTradePnl(pnlSol: number, scenario: number, tokenMint: string): void {
const p = new Point('trade_pnl')
.tag('scenario', `${scenario}ms`)
.tag('token_mint', tokenMint)
.floatField('pnl_sol', pnlSol);
this.writePoint(p);
}
recordExcursion(mfeSol: number, maeSol: number, scenario: number, tokenMint: string): void {
const p = new Point('trade_excursion')
.tag('scenario', `${scenario}ms`)
.tag('token_mint', tokenMint)
.floatField('mfe_sol', mfeSol)
.floatField('mae_sol', maeSol);
this.writePoint(p);
}
async close(): Promise<void> {
if (this.writeApi) {
logger.info('Closing InfluxDB metrics writer...');
try {
await this.writeApi.close();
logger.info('InfluxDB metrics writer closed.');
} catch (error) {
logger.error('Error closing InfluxDB metrics writer', error);
}
}
}
}
// In-Memory/Mock Metrics Provider for local tests and offline dev
export class MockMetricsProvider implements IMetricsProvider {
recordWalletDetectionLatency(_latencyMs: number, _wallet: string): void {}
recordSignalProcessingLatency(_latencyMs: number): void {}
recordQuoteLatency(_latencyMs: number, _provider: string): void {}
recordExecutionLatency(_latencyMs: number, _scenario: number): void {}
recordPrice(_tokenMint: string, _priceSol: number): void {}
recordPortfolioBalance(_balanceSol: number, _scenario: number): void {}
recordTradePnl(_pnlSol: number, _scenario: number, _tokenMint: string): void {}
recordExcursion(_mfeSol: number, _maeSol: number, _scenario: number, _tokenMint: string): void {}
}