feat: No-Stop-Grid-Variante (--no-stop, --pair) — erstes Edge-Signal auf XRP
XRP-Datenanalyse: nie enge Ranges, breite Bänder → No-Stop-Design. OOS-PF 2.0-2.74, Volldurchlauf +49% bei 10% MaxDD. Gate formal ❌ (Worst-Window + Ratio), Tail-Risiko dokumentiert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,12 @@ export interface GridParams {
|
||||
adxMax: number; // Grid nur aktiv im Seitwärtsregime (ADX < adxMax)
|
||||
atrPeriod: number;
|
||||
tfMs: number; // Entscheidungs-Timeframe (Aktivierung/Deaktivierung, ATR/ADX-Basis)
|
||||
/**
|
||||
* true: Range-Breakdown/Ausbruch/Trendbeginn liquidiert alle Lots (harter Stop).
|
||||
* false: Lots werden nie mit Verlust verkauft (nur TP oder end_of_data);
|
||||
* Re-Center nur, wenn das Grid leer ist und der Preis die Range verlassen hat.
|
||||
*/
|
||||
hardStop: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_GRID_PARAMS: GridParams = {
|
||||
@@ -21,6 +27,7 @@ export const DEFAULT_GRID_PARAMS: GridParams = {
|
||||
adxMax: 20,
|
||||
atrPeriod: 14,
|
||||
tfMs: H4,
|
||||
hardStop: true,
|
||||
};
|
||||
|
||||
export interface GridConfig {
|
||||
@@ -136,9 +143,12 @@ export function runGridBacktest(candles15ByPair: Map<Pair, Candle[]>, cfg: GridC
|
||||
|
||||
const g = grids.get(pair);
|
||||
if (g) {
|
||||
const trendStart = !Number.isNaN(ctx.adx[i]) && ctx.adx[i] >= p.adxMax + 5; // Hysterese
|
||||
if (bar.close < g.stopPrice || bar.close > g.upperExit || trendStart) {
|
||||
liquidate(pair, barCloseTs, bar.close, 'grid_stop');
|
||||
const outOfRange = bar.close < g.stopPrice || bar.close > g.upperExit;
|
||||
if (p.hardStop) {
|
||||
const trendStart = !Number.isNaN(ctx.adx[i]) && ctx.adx[i] >= p.adxMax + 5; // Hysterese
|
||||
if (outOfRange || trendStart) liquidate(pair, barCloseTs, bar.close, 'grid_stop');
|
||||
} else if (outOfRange && g.lots.every((l) => !l)) {
|
||||
grids.delete(pair); // leeres Grid folgt dem Preis (Re-Center ohne Verlust)
|
||||
}
|
||||
} else if (
|
||||
!Number.isNaN(ctx.atr[i]) &&
|
||||
@@ -146,7 +156,7 @@ export function runGridBacktest(candles15ByPair: Map<Pair, Candle[]>, cfg: GridC
|
||||
ctx.adx[i] < p.adxMax
|
||||
) {
|
||||
const spacing = p.spacingAtrMult * ctx.atr[i];
|
||||
const budgetPerLevel = equity() / PAIRS.length / p.gridLevels;
|
||||
const budgetPerLevel = equity() / contexts.length / p.gridLevels;
|
||||
if (spacing > 0 && budgetPerLevel >= cfg.minNotionalUsdt) {
|
||||
grids.set(pair, {
|
||||
center: bar.close,
|
||||
|
||||
@@ -19,7 +19,12 @@ const PARAMS = {
|
||||
gridLevels: argNum('--levels', DEFAULT_GRID_PARAMS.gridLevels),
|
||||
adxMax: argNum('--adx', DEFAULT_GRID_PARAMS.adxMax),
|
||||
tfMs: argNum('--tf', DEFAULT_GRID_PARAMS.tfMs / 60000) * 60000, // Minuten
|
||||
hardStop: !process.argv.includes('--no-stop'),
|
||||
};
|
||||
const ONLY_PAIR = (() => {
|
||||
const i = process.argv.indexOf('--pair');
|
||||
return i >= 0 ? (process.argv[i + 1] as Pair) : null;
|
||||
})();
|
||||
const START_CAPITAL = 1000;
|
||||
const EXEC = DEFAULT_EXEC;
|
||||
const MIN_NOTIONAL = 10;
|
||||
@@ -29,6 +34,7 @@ let dataFrom = 0;
|
||||
let dataTo = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
for (const pair of PAIRS) {
|
||||
if (ONLY_PAIR && pair !== ONLY_PAIR) continue;
|
||||
const cov = await getCoverage(pair);
|
||||
if (!cov.from || !cov.to) throw new Error(`Keine Candles für ${pair} — erst 'bun run backfill' ausführen.`);
|
||||
candles15ByPair.set(pair, await getCandles(pair));
|
||||
@@ -37,7 +43,7 @@ for (const pair of PAIRS) {
|
||||
console.log(`${pair}: ${cov.count} Candles (${cov.from.toISOString()} → ${cov.to.toISOString()})`);
|
||||
}
|
||||
|
||||
console.log(`\nATR-Grid (fix: spacing ${PARAMS.spacingAtrMult}×ATR, ${PARAMS.gridLevels} Levels, ADX < ${PARAMS.adxMax}, tf ${PARAMS.tfMs / 60000}m, long-only)`);
|
||||
console.log(`\nATR-Grid (fix: spacing ${PARAMS.spacingAtrMult}×ATR, ${PARAMS.gridLevels} Levels, ADX < ${PARAMS.adxMax}, tf ${PARAMS.tfMs / 60000}m, ${PARAMS.hardStop ? 'hard-stop' : 'NO-STOP'}${ONLY_PAIR ? ', nur ' + ONLY_PAIR : ''}, long-only)`);
|
||||
console.log(`Walk-Forward über ${((dataTo - dataFrom) / 86400000).toFixed(0)} Tage…\n`);
|
||||
|
||||
const windows = buildWindows(dataFrom, dataTo);
|
||||
|
||||
Reference in New Issue
Block a user