Global Services provide entry points for runtime operations that require validation and delegation to connection services. Unlike schema services (which store configurations) and command services (which orchestrate execution), global services act as facades that coordinate validation, logging, and delegation for specific subsystems.
The framework provides four Global Services, each managing a distinct domain:
| Global Service Class | Domain | Primary Responsibilities |
|---|---|---|
RiskGlobalService |
Portfolio risk management | Validates risk profiles, delegates position tracking to RiskConnectionService |
SizingGlobalService |
Position sizing | Validates sizing configurations, delegates calculations to SizingConnectionService |
PartialGlobalService |
Profit/loss milestones | Validates strategies, delegates milestone tracking to PartialConnectionService |
OptimizerGlobalService |
LLM strategy generation | Validates optimizer configurations, delegates code generation to OptimizerConnectionService |
For information about the overall service layer organization, see Service Architecture Overview. For details on the services that Global Services delegate to, see Connection Services, Schema Services, and Validation Services.
Global Services occupy a specific niche in the service architecture distinct from other layers.
Purpose: This diagram shows how Global Services fit between client classes and connection services. Unlike add* functions which access schema/validation services directly, global services provide validated entry points for runtime operations.
| Layer | Purpose | State Management | Used By |
|---|---|---|---|
| Schema Services | Store registered configurations | In-memory ToolRegistry | add* functions, Connection Services |
| Validation Services | Enforce registration rules | Stateless (memoized checks) | add* functions, Global Services |
| Connection Services | Create/cache client instances | Memoized client instances per key | Global Services, Core Services |
| Global Services | Coordinate validation + delegation | Stateless (delegates to Connection) | Client classes (ClientStrategy, etc.) |
| Command Services | Orchestrate execution workflows | Stateless (delegates to Logic) | Utility classes (Backtest, Live, Walker) |
Key distinction: Global Services are runtime facades used by client classes during execution. Schema Services are configuration stores used during setup. Command Services are execution orchestrators used by utility classes.
All Global Services follow a consistent three-step pattern for public methods:
Purpose: This diagram shows the standard three-step pattern that all Global Service methods follow: log the operation, validate component existence, then delegate to the corresponding Connection Service.
Every public method in a Global Service follows this template:
// Pattern from PartialGlobalService.profit()
public profit = async (
symbol: string,
data: ISignalRow,
currentPrice: number,
revenuePercent: number,
backtest: boolean,
when: Date
) => {
// Step 1: Log operation with context
this.loggerService.log("partialGlobalService profit", {
symbol,
data,
currentPrice,
revenuePercent,
backtest,
when,
});
// Step 2: Validate component existence (memoized)
this.validate(data.strategyName, "partialGlobalService profit");
// Step 3: Delegate to Connection Service
return await this.partialConnectionService.profit(
symbol,
data,
currentPrice,
revenuePercent,
backtest,
when
);
};
All Global Services inject three types of dependencies via the DI container:
Purpose: This diagram shows the dependency injection pattern used by PartialGlobalService. All dependencies are injected using the inject() function with TYPES symbols.
| Dependency Type | Instance | Purpose | Usage |
|---|---|---|---|
| Logger | LoggerService |
Operation logging | Called at method entry with context |
| Connection | *ConnectionService |
Client factory | Delegates operations after validation |
| Validation | *ValidationService |
Schema checks | Called by memoized validate() |
| Schema | *SchemaService |
Configuration retrieval | Accessed to check related components |
Example from PartialGlobalService:
src/lib/services/global/PartialGlobalService.ts:40-74
private readonly loggerService = inject<LoggerService>(TYPES.loggerService);
private readonly partialConnectionService = inject<PartialConnectionService>(
TYPES.partialConnectionService
);
private readonly strategyValidationService = inject<StrategyValidationService>(
TYPES.strategyValidationService
);
private readonly strategySchemaService = inject<StrategySchemaService>(
TYPES.strategySchemaService
);
private readonly riskValidationService = inject<RiskValidationService>(
TYPES.riskValidationService
);
Global Services use memoization to avoid redundant validation calls for the same component.
Purpose: This sequence diagram shows how memoization prevents redundant validation. The first call performs validation and caches the result. Subsequent calls for the same strategy return immediately from cache.
The validate() method is wrapped with memoize() from functools-kit:
src/lib/services/global/PartialGlobalService.ts:77-95
private validate = memoize(
// Cache key: strategy name
([strategyName]) => `${strategyName}`,
// Validation logic (only runs once per key)
(strategyName: string, methodName: string) => {
this.loggerService.log("partialGlobalService validate", {
strategyName,
methodName,
});
// Validate strategy exists
this.strategyValidationService.validate(strategyName, methodName);
// Validate associated risk profiles
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
riskName && this.riskValidationService.validate(riskName, methodName);
riskList && riskList.forEach((riskName) =>
this.riskValidationService.validate(riskName, methodName)
);
}
);
Key aspects:
PartialGlobalService coordinates partial profit/loss milestone tracking. It validates strategies and delegates milestone operations to PartialConnectionService.
Purpose: This diagram shows PartialGlobalService's role in the partial tracking system. ClientStrategy calls the global service, which validates and delegates to PartialConnectionService, which manages ClientPartial instances.
| Method | Parameters | Description |
|---|---|---|
profit() |
symbol, data, currentPrice, revenuePercent, backtest, when |
Processes profit state, emits events for new levels (10%, 20%, etc) |
loss() |
symbol, data, currentPrice, lossPercent, backtest, when |
Processes loss state, emits events for new levels (-10%, -20%, etc) |
clear() |
symbol, data, priceClose, backtest |
Clears milestone state when signal closes |
Example usage from ClientStrategy:
src/lib/services/global/PartialGlobalService.ts:110-175
// Called during signal monitoring when in profit
public profit = async (
symbol: string,
data: ISignalRow,
currentPrice: number,
revenuePercent: number,
backtest: boolean,
when: Date
) => {
this.loggerService.log("partialGlobalService profit", {
symbol,
data,
currentPrice,
revenuePercent,
backtest,
when,
});
this.validate(data.strategyName, "partialGlobalService profit");
return await this.partialConnectionService.profit(
symbol,
data,
currentPrice,
revenuePercent,
backtest,
when
);
};
Validation flow:
StrategyValidationServiceriskName and riskListRiskValidationServicePartialConnectionServiceRiskGlobalService coordinates portfolio-level risk management. It validates risk profiles and delegates position tracking to RiskConnectionService. (Not fully detailed in provided files, but follows the same pattern as PartialGlobalService.)
SizingGlobalService coordinates position sizing calculations. It validates sizing configurations and delegates calculations to SizingConnectionService. (Not fully detailed in provided files, but follows the same pattern.)
OptimizerGlobalService coordinates LLM-based strategy generation. It validates optimizer configurations and delegates code generation to OptimizerConnectionService. (Not fully detailed in provided files, but follows the same pattern.)
Global Services are primarily used by client classes during runtime execution, not by public API functions.
Purpose: This sequence diagram shows the complete call chain from ClientStrategy through PartialGlobalService to ClientPartial. Global Services act as validated entry points, not as direct public APIs.
Client classes receive Global Services via their constructor parameters:
// From IStrategyParams interface (not shown but inferred)
interface IStrategyParams {
partial: PartialGlobalService; // Injected global service
risk: RiskGlobalService; // Injected global service
sizing: SizingGlobalService; // Injected global service
// ...
}
// ClientStrategy uses injected services
class ClientStrategy {
constructor(readonly params: IStrategyParams) {}
async monitorSignal(...) {
// Use injected PartialGlobalService
if (revenuePercent > 0) {
await this.params.partial.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
}
}
}
Key points:
this.params.*GlobalServiceadd*, list*) do NOT use Global ServicesGlobal Services are registered in the dependency injection container during framework initialization.
{
provide(TYPES.sizingGlobalService, () => new SizingGlobalService());
provide(TYPES.riskGlobalService, () => new RiskGlobalService());
provide(TYPES.optimizerGlobalService, () => new OptimizerGlobalService());
provide(TYPES.partialGlobalService, () => new PartialGlobalService());
}
const globalServices = {
sizingGlobalService: inject<SizingGlobalService>(TYPES.sizingGlobalService),
riskGlobalService: inject<RiskGlobalService>(TYPES.riskGlobalService),
optimizerGlobalService: inject<OptimizerGlobalService>(
TYPES.optimizerGlobalService
),
partialGlobalService: inject<PartialGlobalService>(
TYPES.partialGlobalService
),
};
All services are included in the backtest export object src/lib/index.ts:225-246, making them accessible as:
backtest.sizingGlobalServicebacktest.riskGlobalServicebacktest.optimizerGlobalServicebacktest.partialGlobalServiceconst globalServices = {
sizingGlobalService: Symbol('sizingGlobalService'),
riskGlobalService: Symbol('riskGlobalService'),
optimizerGlobalService: Symbol('optimizerGlobalService'),
partialGlobalService: Symbol('partialGlobalService'),
}
Key aspects:
provide()inject() callGlobal Services exhibit these consistent patterns across the framework:
Global Services maintain no state themselves. They delegate state management to:
Validation is memoized by component name to avoid redundant schema checks:
// Pattern from RiskGlobalService
private validate = memoize(
([riskName]) => `${riskName}`, // Cache key
async (riskName: RiskName) => {
this.loggerService.log("riskGlobalService validate", {
riskName,
});
this.riskValidationService.validate(
riskName,
"riskGlobalService validate"
);
}
);
The cache key is the component name string. First invocation performs validation, subsequent calls return immediately.
Every public method logs its invocation with context:
public checkSignal = async (
params: IRiskCheckArgs,
context: { riskName: RiskName }
) => {
this.loggerService.log("riskGlobalService checkSignal", {
symbol: params.symbol,
context,
});
await this.validate(context.riskName);
return await this.riskConnectionService.checkSignal(params, context);
};
Log entries include:
"riskGlobalService checkSignal")Each Global Service manages exactly one component type or execution mode:
RiskGlobalService → Risk profiles onlyStrategyGlobalService → Strategies onlyBacktestGlobalService → Backtest execution onlyWalkerGlobalService → Both walker components AND walker execution (special case)Purpose: This diagram summarizes the complete delegation flow for both Component and Execution Global Services. Both types perform validation first, but Component services delegate to Connection Services while Execution services delegate to Logic Services.