Seed leg splits per prefix group so like accounts split targets alike
Like accounts in a batch previously carved legs with independent Math.random, so near-identical day targets could split very differently. Leg fractions are now drawn from groupLegFraction(prefix, tradeDate, legIndex) — FNV-1a seeded like dailyBump — so accounts of the same account type on the same leg of the same day split identically when their remaining targets match, and proportionally close otherwise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3516e6c288
commit
5d2f4d607a
+10
-4
@@ -12,7 +12,7 @@ import { getClients } from './clients';
|
|||||||
import { getTradableFirms } from './firm-catalog';
|
import { getTradableFirms } from './firm-catalog';
|
||||||
import { getAccountConfig } from './account-type-resolver';
|
import { getAccountConfig } from './account-type-resolver';
|
||||||
import {
|
import {
|
||||||
combineCmeSessions, computeDayPlan, pickLegAmount, resolveEffectiveConfig, currentTradeDateCT,
|
combineCmeSessions, computeDayPlan, groupLegFraction, pickLegAmount, resolveEffectiveConfig, currentTradeDateCT,
|
||||||
LEG_COMPLETION_EPSILON, MAX_LEGS_PER_DAY, POINT_VALUES,
|
LEG_COMPLETION_EPSILON, MAX_LEGS_PER_DAY, POINT_VALUES,
|
||||||
type DayPlan,
|
type DayPlan,
|
||||||
} from './trading-logic';
|
} from './trading-logic';
|
||||||
@@ -354,8 +354,12 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Auto', symbol: string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trade one leg toward today's remaining target. Split-allowed big days carve a
|
// Trade one leg toward today's remaining target. Split-allowed big days carve a
|
||||||
// random ≥$800 piece; everything else trades the full remaining amount in one go.
|
// ≥$800 piece; everything else trades the full remaining amount in one go. The
|
||||||
const legAmount = item.plan.splitAllowed ? pickLegAmount(item.plan.remainingToday) : item.plan.remainingToday;
|
// carve fraction is seeded per (prefix, date, leg number) so like accounts in a
|
||||||
|
// batch split their targets the same way, or close to it when remainders differ.
|
||||||
|
const legAmount = item.plan.splitAllowed
|
||||||
|
? pickLegAmount(item.plan.remainingToday, () => groupLegFraction(item.prefix, tradeDate, legsToday(acc.id, tradeDate)))
|
||||||
|
: item.plan.remainingToday;
|
||||||
recordLeg(acc.id, tradeDate);
|
recordLeg(acc.id, tradeDate);
|
||||||
|
|
||||||
const rawContracts = Math.max(1, Math.ceil(legAmount / 1000));
|
const rawContracts = Math.max(1, Math.ceil(legAmount / 1000));
|
||||||
@@ -563,7 +567,9 @@ export async function copyTrade() {
|
|||||||
const { client, acc, contract } = item;
|
const { client, acc, contract } = item;
|
||||||
const cfg = getAccountConfig(acc.id).accountType!;
|
const cfg = getAccountConfig(acc.id).accountType!;
|
||||||
|
|
||||||
const legAmount = item.plan.splitAllowed ? pickLegAmount(item.plan.remainingToday) : item.plan.remainingToday;
|
const legAmount = item.plan.splitAllowed
|
||||||
|
? pickLegAmount(item.plan.remainingToday, () => groupLegFraction(item.prefix, tradeDate, legsToday(acc.id, tradeDate)))
|
||||||
|
: item.plan.remainingToday;
|
||||||
recordLeg(acc.id, tradeDate);
|
recordLeg(acc.id, tradeDate);
|
||||||
|
|
||||||
const rawContracts = Math.max(1, Math.ceil(legAmount / 1000));
|
const rawContracts = Math.max(1, Math.ceil(legAmount / 1000));
|
||||||
|
|||||||
@@ -92,6 +92,22 @@ export function currentTradeDateCT(now: Date = new Date()): string {
|
|||||||
return new Date(date).toISOString().slice(0, 10);
|
return new Date(date).toISOString().slice(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deterministic fraction in [0, 1) for a (prefix group, trade date, leg index) triple.
|
||||||
|
* Like accounts (same account-type prefix) carving the same leg of the same day draw the
|
||||||
|
* same fraction, so pickLegAmount splits their targets identically when their remaining
|
||||||
|
* amounts match and proportionally close when they differ (bumps, epsilon leftovers).
|
||||||
|
*/
|
||||||
|
export function groupLegFraction(prefix: string, tradeDate: string, legIndex: number): number {
|
||||||
|
const key = `${prefix}|${tradeDate}|${legIndex}`;
|
||||||
|
let hash = 0x811c9dc5;
|
||||||
|
for (let i = 0; i < key.length; i++) {
|
||||||
|
hash ^= key.charCodeAt(i);
|
||||||
|
hash = Math.imul(hash, 0x01000193) >>> 0;
|
||||||
|
}
|
||||||
|
return hash / 0x100000000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pick the next leg to trade toward today's remaining target.
|
* Pick the next leg to trade toward today's remaining target.
|
||||||
* remaining ≤ BIG_DAY_THRESHOLD → trade it all in one final leg; otherwise carve a random
|
* remaining ≤ BIG_DAY_THRESHOLD → trade it all in one final leg; otherwise carve a random
|
||||||
|
|||||||
Reference in New Issue
Block a user