Connection Services implement memoized client instance management within the service layer architecture. Each Connection Service is responsible for creating and caching client instances (ClientStrategy, ClientExchange, ClientFrame, ClientRisk, ClientSizing) based on their respective schema names. These services inject required dependencies into client constructors and ensure one instance exists per registered schema name.
This document covers all five Connection Services: StrategyConnectionService, ExchangeConnectionService, FrameConnectionService, RiskConnectionService, and SizingConnectionService. For schema registration, see page 7.3 Schema Services. For client implementations, see page 6 Core Business Logic. For routing context, see page 3.3 Context Propagation.
Connection Services implement the factory pattern with memoization to manage client instance lifecycles. Each service injects dependencies from Schema Services and other infrastructure services into client constructors, then caches the resulting instances by name.
| Connection Service | Client Class | Cache Key | Interface Implemented |
|---|---|---|---|
| StrategyConnectionService | ClientStrategy | strategyName | IStrategy |
| ExchangeConnectionService | ClientExchange | exchangeName | IExchange |
| FrameConnectionService | ClientFrame | frameName | IFrame |
| RiskConnectionService | ClientRisk | riskName | IRisk |
| SizingConnectionService | ClientSizing | sizingName | ISizing |
All Connection Services use memoize from functools-kit to cache client instances. The pattern ensures each schema name maps to exactly one client instance for the application lifetime.
Each Connection Service defines a key function that extracts the cache key from arguments:
Example from StrategyConnectionService src/lib/services/connection/StrategyConnectionService.ts:76-94:
private getStrategy = memoize(
([strategyName]) => `${strategyName}`, // Key function: extracts strategyName
(strategyName: StrategyName) => { // Factory function: creates instance
const { riskName, getSignal, interval, callbacks } =
this.strategySchemaService.get(strategyName);
return new ClientStrategy({
interval,
execution: this.executionContextService,
method: this.methodContextService,
logger: this.loggerService,
exchange: this.exchangeConnectionService,
risk: riskName ? this.riskConnectionService.getRisk(riskName) : NOOP_RISK,
riskName,
strategyName,
getSignal,
callbacks,
});
}
);
Example from RiskConnectionService src/lib/services/connection/RiskConnectionService.ts:56-65:
public getRisk = memoize(
([riskName]) => `${riskName}`, // Key function
(riskName: RiskName) => { // Factory function
const schema = this.riskSchemaService.get(riskName);
return new ClientRisk({
...schema,
logger: this.loggerService,
});
}
);
Connection Services inject dependencies into client constructors, combining schema configuration with infrastructure services.
StrategyConnectionService src/lib/services/connection/StrategyConnectionService.ts:76-94:
| Injected Dependency | Type | Purpose |
|---|---|---|
interval |
SignalInterval | From schema: throttling interval |
getSignal |
Function | From schema: signal generation logic |
callbacks |
Partial |
From schema: lifecycle hooks |
riskName |
RiskName | From schema: risk profile identifier |
strategyName |
StrategyName | From schema: instance identifier |
logger |
LoggerService | Service layer: logging |
execution |
ExecutionContextService | Service layer: when/symbol/backtest |
method |
MethodContextService | Service layer: strategy/exchange/frame names |
exchange |
ExchangeConnectionService | Service layer: market data access |
risk |
IRisk | Service layer: risk checking (via RiskConnectionService) |
RiskConnectionService src/lib/services/connection/RiskConnectionService.ts:56-65:
| Injected Dependency | Type | Purpose |
|---|---|---|
riskName |
RiskName | From schema: instance identifier |
validations |
Array | From schema: custom validation functions |
callbacks |
Partial |
From schema: lifecycle hooks |
logger |
LoggerService | Service layer: logging |
Manages ClientStrategy instances by strategyName. Implements the IStrategy interface src/interfaces/Strategy.interface.ts:298-344 and routes all strategy operations to memoized instances.
Calls ClientStrategy.tick() for the current strategy. Routes to memoized instance via methodContextService.context.strategyName.
Returns: Promise<IStrategyTickResult>
Flow:
getStrategy(strategyName) to get cached instancestrategy.waitForInit() for persistence recovery src/lib/services/connection/StrategyConnectionService.ts:109strategy.tick() src/lib/services/connection/StrategyConnectionService.ts:110Calls ClientStrategy.backtest(candles) for the current strategy. Fast-forwards through historical candles.
Parameters: candles: ICandleData[]
Returns: Promise<IStrategyBacktestResult>
Flow: Similar to tick() but calls strategy.backtest(candles) src/lib/services/connection/StrategyConnectionService.ts:132-150
Calls ClientStrategy.stop() to prevent new signal generation. Active signals continue monitoring.
Parameters: strategyName: StrategyName
When a strategy has no riskName, a no-op risk implementation is injected src/lib/services/connection/StrategyConnectionService.ts:25-29:
const NOOP_RISK: IRisk = {
checkSignal: () => Promise.resolve(true),
addSignal: () => Promise.resolve(),
removeSignal: () => Promise.resolve(),
}
Manages ClientRisk instances by riskName. Implements IRisk interface methods and routes risk validation operations to memoized instances. Multiple strategies can share the same ClientRisk instance by specifying the same riskName.
The getRisk method src/lib/services/connection/RiskConnectionService.ts:56-65 creates ClientRisk instances with minimal dependencies:
public getRisk = memoize(
([riskName]) => `${riskName}`,
(riskName: RiskName) => {
const schema = this.riskSchemaService.get(riskName);
return new ClientRisk({
...schema, // Spreads: riskName, validations, callbacks
logger: this.loggerService,
});
}
);
Validates if a signal should be allowed based on risk limits. Delegates to ClientRisk.checkSignal().
Parameters:
params: IRiskCheckArgs - Contains symbol, strategyName, exchangeName, currentPrice, timestampcontext: { riskName: RiskName } - Identifies which risk instance to useReturns: Promise<boolean> - true if allowed, false if rejected
Registers an opened position in the risk tracker. Called after signal is opened.
Parameters:
symbol: stringcontext: { strategyName: string; riskName: RiskName }Removes a closed position from the risk tracker. Called after signal is closed.
Parameters:
symbol: stringcontext: { strategyName: string; riskName: RiskName }Multiple strategies with the same riskName share one ClientRisk instance src/lib/services/connection/RiskConnectionService.ts:56-65. This enables cross-strategy position tracking:
The remaining Connection Services follow identical patterns to StrategyConnectionService and RiskConnectionService.
Manages ClientExchange instances by exchangeName. Routes market data operations (getCandles, getAveragePrice, formatPrice, formatQuantity).
Injected Dependencies:
Memoized Method: getExchange(exchangeName) creates ClientExchange instances
Manages ClientFrame instances by frameName. Routes timeframe generation for backtest periods.
Injected Dependencies:
Memoized Method: getFrame(frameName) creates ClientFrame instances
Note: Not used in live mode where frameName is empty string.
Manages ClientSizing instances by sizingName. Routes position size calculations (fixed-percentage, kelly-criterion, atr-based).
Injected Dependencies:
Memoized Method: getSizing(sizingName) creates ClientSizing instances
Connection Services integrate with multiple layers of the architecture, serving as the critical routing infrastructure.
| Source | Connection Service | Destination | Purpose |
|---|---|---|---|
| Logic Services | StrategyConnectionService | ClientStrategy | Signal evaluation and backtest |
| ClientStrategy | ExchangeConnectionService | ClientExchange | Candle data and VWAP |
| Logic Services | ExchangeConnectionService | ClientExchange | Price formatting |
| Logic Services | FrameConnectionService | ClientFrame | Timeframe generation |
All Connection Services inject LoggerService and log operations with context-enriched metadata src/lib/services/connection/StrategyConnectionService.ts:45, src/lib/services/connection/ExchangeConnectionService.ts:39, src/lib/services/connection/FrameConnectionService.ts:33:
StrategyConnectionService: Logs tick and backtest operations with candle countsExchangeConnectionService: Logs all data fetching with symbol, interval, and limitsFrameConnectionService: Logs timeframe retrieval with symbol