This document describes the global validation parameters that control financial safety constraints in signal generation. These parameters enforce minimum take profit distances, maximum stop loss distances, and signal lifetime limits to protect capital from unprofitable trades, catastrophic losses, and strategy deadlock.
For information about other configuration parameters like timeout and timing constraints, see Timing Parameters. For an overview of the configuration system, see Global Configuration. For details on how signals are validated during generation, see Signal Generation and Validation.
The framework enforces three critical validation parameters that act as financial guardrails during signal generation. These parameters are part of GLOBAL_CONFIG and can be modified via setConfig() at runtime.
| Parameter | Type | Default | Purpose |
|---|---|---|---|
CC_MIN_TAKEPROFIT_DISTANCE_PERCENT |
number | 0.1 | Minimum percentage distance between priceOpen and priceTakeProfit to ensure profit exceeds trading fees |
CC_MAX_STOPLOSS_DISTANCE_PERCENT |
number | 20 | Maximum percentage distance between priceOpen and priceStopLoss to prevent catastrophic losses |
CC_MAX_SIGNAL_LIFETIME_MINUTES |
number | 1440 | Maximum signal duration in minutes to prevent eternal signals blocking risk limits |
These validations occur in the VALIDATE_SIGNAL_FN function within ClientStrategy, which is called before every signal is created. Signals that fail validation are rejected immediately with descriptive error messages.
Trading fees (typically 0.1% per side) create a minimum profit threshold. If priceTakeProfit is too close to priceOpen, the gross profit will be consumed by fees, resulting in a net loss despite hitting the take profit target.
Example Scenario:
priceOpen = 42000, priceTakeProfit = 42010 (0.024% profit)Diagram: Take Profit Distance Validation Flow
The validation calculates the percentage distance between entry price and take profit target, then compares it against CC_MIN_TAKEPROFIT_DISTANCE_PERCENT. For long positions, TP must be above entry. For short positions, TP must be below entry.
Long Position Validation (lines 87-97):
const tpDistancePercent = ((signal.priceTakeProfit - signal.priceOpen) / signal.priceOpen) * 100;
if (tpDistancePercent < GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
errors.push(`Long: TakeProfit too close to priceOpen...`);
}
Short Position Validation (lines 127-137):
const tpDistancePercent = ((signal.priceOpen - signal.priceTakeProfit) / signal.priceOpen) * 100;
if (tpDistancePercent < GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
errors.push(`Short: TakeProfit too close to priceOpen...`);
}
The default value of 0.1% is intentionally conservative:
0 to disable validation (not recommended for production)Excessively wide stop losses can expose the portfolio to catastrophic single-trade losses. A stop loss positioned 50% below entry would lose half the position size in one trade, potentially destroying the strategy's expected value.
Example Scenario:
priceOpen = 42000, priceStopLoss = 20000 (52.4% loss)Diagram: Stop Loss Distance Validation Flow
The validation calculates the percentage distance between entry price and stop loss target, then compares it against CC_MAX_STOPLOSS_DISTANCE_PERCENT. For long positions, SL must be below entry. For short positions, SL must be above entry.
Long Position Validation (lines 100-110):
const slDistancePercent = ((signal.priceOpen - signal.priceStopLoss) / signal.priceOpen) * 100;
if (slDistancePercent > GLOBAL_CONFIG.CC_MAX_STOPLOSS_DISTANCE_PERCENT) {
errors.push(`Long: StopLoss too far from priceOpen...`);
}
Short Position Validation (lines 140-150):
const slDistancePercent = ((signal.priceStopLoss - signal.priceOpen) / signal.priceOpen) * 100;
if (slDistancePercent > GLOBAL_CONFIG.CC_MAX_STOPLOSS_DISTANCE_PERCENT) {
errors.push(`Short: StopLoss too far from priceOpen...`);
}
The default value of 20% represents a reasonable maximum loss per signal:
5-10% for conservative strategies100+%) in productionSignals with excessively long minuteEstimatedTime can create strategy deadlock by occupying risk limits indefinitely. If a signal expects to remain active for 30+ days, it blocks new signals from being generated, effectively freezing the strategy.
Example Scenario:
minuteEstimatedTime = 50000 minutes (34.7 days)maxConcurrentPositions = 3Diagram: Signal Lifetime Validation Flow
The validation compares minuteEstimatedTime directly against CC_MAX_SIGNAL_LIFETIME_MINUTES. Error messages include human-readable day conversions for clarity.
Validation Implementation (lines 161-171):
if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
const days = (signal.minuteEstimatedTime / 60 / 24).toFixed(1);
const maxDays = (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES / 60 / 24).toFixed(0);
errors.push(
`minuteEstimatedTime too large (${signal.minuteEstimatedTime} minutes = ${days} days). ` +
`Maximum: ${GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES} minutes (${maxDays} days) to prevent strategy deadlock. ` +
`Eternal signals block risk limits and prevent new trades.`
);
}
The default value of 1440 minutes (1 day):
999999) in productionThe following diagram shows how validation parameters integrate into the signal generation pipeline:
Diagram: Complete Signal Validation Flow with Validation Parameters
The validation occurs in VALIDATE_SIGNAL_FN at src/client/ClientStrategy.ts:40-185. The function accumulates all validation errors into an array, then throws a single descriptive error if any validations fail. This provides comprehensive feedback to strategy developers.
Key Validation Stages:
CC_MIN_TAKEPROFIT_DISTANCE_PERCENTCC_MAX_STOPLOSS_DISTANCE_PERCENTCC_MAX_SIGNAL_LIFETIME_MINUTESValidation parameters can be modified at runtime using the setConfig() function. This is typically done during initialization or in test environments.
import { setConfig } from 'backtest-kit';
setConfig({
CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: 0.5, // Require 0.5% minimum profit
CC_MAX_STOPLOSS_DISTANCE_PERCENT: 10, // Allow max 10% stop loss
CC_MAX_SIGNAL_LIFETIME_MINUTES: 720, // Max 12 hours per signal
});
| Use Case | Configuration | Rationale |
|---|---|---|
| Disable Validation (Testing) | Set to 0, 100, 999999 respectively |
Allows testing edge cases without validation constraints |
| Conservative Trading | Set to 0.5%, 5%, 360 min |
Tighter constraints for risk-averse strategies |
| Volatile Markets | Set to 0.2%, 30%, 2880 min |
Looser constraints for high-volatility assets |
| Long-term Holding | Set to 1%, 20%, 10080 min |
Allow multi-day positions with wider stops |
Test files disable validation by default to isolate signal logic testing from validation constraints:
// test/config/setup.mjs
setConfig({
CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: 0, // No TP distance check
CC_MAX_STOPLOSS_DISTANCE_PERCENT: 100, // Allow any SL
CC_MAX_SIGNAL_LIFETIME_MINUTES: 999999, // No lifetime limit
});
Specific validation tests override these defaults:
// test/e2e/sanitize.test.mjs
test("Micro-profit validation", async () => {
setConfig({
CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: 0.3, // Enable TP validation
});
// ... test code
});
Validation failures produce detailed error messages that help strategy developers diagnose issues:
Long: TakeProfit too close to priceOpen (0.024%).
Minimum distance: 0.3% to cover trading fees.
Current: TP=42010, Open=42000
Long: StopLoss too far from priceOpen (52.381%).
Maximum distance: 20% to protect capital.
Current: SL=20000, Open=42000
minuteEstimatedTime too large (50000 minutes = 34.7 days).
Maximum: 1440 minutes (1 days) to prevent strategy deadlock.
Eternal signals block risk limits and prevent new trades.
Multiple validation failures are combined into a single error message:
Invalid signal for long position:
Long: TakeProfit too close to priceOpen (0.024%). Minimum distance: 0.3% to cover trading fees. Current: TP=42010, Open=42000
Long: StopLoss too far from priceOpen (52.381%). Maximum distance: 20% to protect capital. Current: SL=20000, Open=42000
minuteEstimatedTime too large (50000 minutes = 34.7 days). Maximum: 1440 minutes (1 days) to prevent strategy deadlock. Eternal signals block risk limits and prevent new trades.
This comprehensive error output allows developers to fix all validation issues in a single iteration.
The table below summarizes default values, their safety guarantees, and when to adjust them:
| Parameter | Default | Safety Guarantee | When to Increase | When to Decrease |
|---|---|---|---|---|
CC_MIN_TAKEPROFIT_DISTANCE_PERCENT |
0.1% | Prevents fee-eating micro-profits | Higher fee exchanges (0.2%+) | Lower fee exchanges or maker rebates |
CC_MAX_STOPLOSS_DISTANCE_PERCENT |
20% | Prevents catastrophic single-trade losses | High-volatility assets (crypto, meme coins) | Stable assets, conservative risk appetite |
CC_MAX_SIGNAL_LIFETIME_MINUTES |
1440 (1 day) | Prevents strategy deadlock from eternal signals | Swing trading (1 week), position trading (1 month) | Intraday strategies (2-4 hours) |
These validation parameters work in conjunction with risk profile limits (see Risk Profiles):
Diagram: Validation Parameters as First Line of Defense
Validation parameters act as the first line of defense, rejecting signals before they reach the risk management layer. This prevents invalid signals from consuming risk limit slots or triggering custom validations.