Rewrite trader service for V4 P0

This commit is contained in:
Codex
2026-06-26 21:53:22 +08:00
parent 2fe4077164
commit 5d210053d0
184 changed files with 2780 additions and 6945 deletions
@@ -1,299 +1,92 @@
package com.quantai.trader.config;
import com.quantai.trader.enums.TraderExecutionMode;
import com.quantai.trader.enums.TraderRunMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.math.BigDecimal;
import static com.quantai.trader.util.TraderNumbers.requiredText;
@ConfigurationProperties(prefix = "trader")
public class TraderProperties {
private String serviceName = "quant-trader-service";
private TraderRunMode runMode = TraderRunMode.REPLAY;
private String symbol = "BTCUSDT";
private String featureVersion = "trader_feature_v0";
private String labelVersion = "trader_label_v0";
private Playbook playbook = new Playbook();
private Replay replay = new Replay();
private Integration integration = new Integration();
private Risk risk = new Risk();
private Sizing sizing = new Sizing();
private DataSource dataSource = new DataSource();
public String getServiceName() {
return serviceName;
public record TraderProperties(
String serviceName,
TraderRunMode runMode,
String symbol,
Artifact artifact,
Feedback feedback,
Execution execution,
Runtime runtime,
Outbox outbox,
Release release,
Risk risk,
PositionManager positionManager
) {
public TraderProperties {
serviceName = defaultText(serviceName, "quant-trader-service");
runMode = runMode == null ? TraderRunMode.SHADOW : runMode;
symbol = defaultText(symbol, "BTC-USDT-PERP");
artifact = artifact == null ? new Artifact("trader-v4-btc-p0", "cal-v4-btc-p0", "pm-v4-btc-p0", ".") : artifact;
feedback = feedback == null ? new Feedback(false) : feedback;
execution = execution == null ? new Execution(TraderExecutionMode.SHADOW, 3, 1500) : execution;
runtime = runtime == null ? new Runtime("trader:v4", true, false) : runtime;
outbox = outbox == null ? new Outbox(true, 5) : outbox;
release = release == null ? new Release(true, true, true) : release;
risk = risk == null ? new Risk(new BigDecimal("200"), BigDecimal.ONE, new BigDecimal("500")) : risk;
positionManager = positionManager == null ? new PositionManager(BigDecimal.ONE, BigDecimal.ONE) : positionManager;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
private static String defaultText(String value, String defaultValue) {
return value == null || value.isBlank() ? defaultValue : value;
}
public TraderRunMode getRunMode() {
return runMode;
}
public void setRunMode(TraderRunMode runMode) {
this.runMode = runMode;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getFeatureVersion() {
return featureVersion;
}
public void setFeatureVersion(String featureVersion) {
this.featureVersion = featureVersion;
}
public String getLabelVersion() {
return labelVersion;
}
public void setLabelVersion(String labelVersion) {
this.labelVersion = labelVersion;
}
public Playbook getPlaybook() {
return playbook;
}
public void setPlaybook(Playbook playbook) {
this.playbook = playbook;
}
public Replay getReplay() {
return replay;
}
public void setReplay(Replay replay) {
this.replay = replay;
}
public Integration getIntegration() {
return integration;
}
public void setIntegration(Integration integration) {
this.integration = integration;
}
public Risk getRisk() {
return risk;
}
public void setRisk(Risk risk) {
this.risk = risk;
}
public Sizing getSizing() {
return sizing;
}
public void setSizing(Sizing sizing) {
this.sizing = sizing;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public static class Playbook {
private String locationPattern = "classpath:/playbooks/*.yml";
public String getLocationPattern() {
return locationPattern;
}
public void setLocationPattern(String locationPattern) {
this.locationPattern = locationPattern;
public record Artifact(
String modelBundleVersion,
String calibrationBundleVersion,
String pmConfigVersion,
String artifactRoot
) {
public Artifact {
modelBundleVersion = requiredText(modelBundleVersion, "artifact.modelBundleVersion");
calibrationBundleVersion = requiredText(calibrationBundleVersion, "artifact.calibrationBundleVersion");
pmConfigVersion = requiredText(pmConfigVersion, "artifact.pmConfigVersion");
artifactRoot = requiredText(artifactRoot, "artifact.artifactRoot");
}
}
public static class Replay {
private String outputDir = "/Users/zach/Desktop/app/trader/replay-output";
private boolean failOnDataMissing = true;
public record Feedback(boolean httpEnabled) {
}
public String getOutputDir() {
return outputDir;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
public boolean isFailOnDataMissing() {
return failOnDataMissing;
}
public void setFailOnDataMissing(boolean failOnDataMissing) {
this.failOnDataMissing = failOnDataMissing;
public record Execution(TraderExecutionMode mode, int maxApiErrorCount, long maxExchangeLatencyMs) {
public Execution {
mode = mode == null ? TraderExecutionMode.SHADOW : mode;
}
}
public static class Integration {
private String appActionChannel = "JAR_FUTURE";
private boolean httpFeedbackEnabled = false;
public String getAppActionChannel() {
return appActionChannel;
}
public void setAppActionChannel(String appActionChannel) {
this.appActionChannel = appActionChannel;
}
public boolean isHttpFeedbackEnabled() {
return httpFeedbackEnabled;
}
public void setHttpFeedbackEnabled(boolean httpFeedbackEnabled) {
this.httpFeedbackEnabled = httpFeedbackEnabled;
public record Runtime(String redisKeyPrefix, boolean requireRedisForOpenAdd, boolean tradingEnabled) {
public Runtime {
redisKeyPrefix = defaultText(redisKeyPrefix, "trader:v4");
}
}
public static class Risk {
private BigDecimal leverageScreen = BigDecimal.TEN;
private boolean requireOneXNotNegative = true;
private int maxPlannedEntryLegs = 3;
private boolean allowFreeScaleIn = false;
private boolean allowReduceThenAdd = false;
private boolean requireStop = true;
private boolean requireTarget = true;
private boolean requireInvalid = true;
public record Outbox(boolean enabled, int maxRetryCount) {
}
public BigDecimal getLeverageScreen() {
return leverageScreen;
}
public record Release(boolean requireReviewForPaper, boolean requireReviewForLiveProbe, boolean activePointerCheckEnabled) {
}
public void setLeverageScreen(BigDecimal leverageScreen) {
this.leverageScreen = leverageScreen;
}
public boolean isRequireOneXNotNegative() {
return requireOneXNotNegative;
}
public void setRequireOneXNotNegative(boolean requireOneXNotNegative) {
this.requireOneXNotNegative = requireOneXNotNegative;
}
public int getMaxPlannedEntryLegs() {
return maxPlannedEntryLegs;
}
public void setMaxPlannedEntryLegs(int maxPlannedEntryLegs) {
this.maxPlannedEntryLegs = maxPlannedEntryLegs;
}
public boolean isAllowFreeScaleIn() {
return allowFreeScaleIn;
}
public void setAllowFreeScaleIn(boolean allowFreeScaleIn) {
this.allowFreeScaleIn = allowFreeScaleIn;
}
public boolean isAllowReduceThenAdd() {
return allowReduceThenAdd;
}
public void setAllowReduceThenAdd(boolean allowReduceThenAdd) {
this.allowReduceThenAdd = allowReduceThenAdd;
}
public boolean isRequireStop() {
return requireStop;
}
public void setRequireStop(boolean requireStop) {
this.requireStop = requireStop;
}
public boolean isRequireTarget() {
return requireTarget;
}
public void setRequireTarget(boolean requireTarget) {
this.requireTarget = requireTarget;
}
public boolean isRequireInvalid() {
return requireInvalid;
}
public void setRequireInvalid(boolean requireInvalid) {
this.requireInvalid = requireInvalid;
public record Risk(BigDecimal maxDailyLossBps, BigDecimal maxTotalExposureRatio, BigDecimal minLiquidationBufferBps) {
public Risk {
maxDailyLossBps = maxDailyLossBps == null ? new BigDecimal("200") : maxDailyLossBps;
maxTotalExposureRatio = maxTotalExposureRatio == null ? BigDecimal.ONE : maxTotalExposureRatio;
minLiquidationBufferBps = minLiquidationBufferBps == null ? new BigDecimal("500") : minLiquidationBufferBps;
}
}
public static class Sizing {
private String method = "SIGNAL_EXECUTION_RISK_DYNAMIC";
private boolean allowFullInitialEntry = true;
private int maxPlannedEntryLegs = 3;
private BigDecimal maxTotalPositionRatio = BigDecimal.ONE;
private BigDecimal maxSingleLegRatio = BigDecimal.ONE;
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public boolean isAllowFullInitialEntry() {
return allowFullInitialEntry;
}
public void setAllowFullInitialEntry(boolean allowFullInitialEntry) {
this.allowFullInitialEntry = allowFullInitialEntry;
}
public int getMaxPlannedEntryLegs() {
return maxPlannedEntryLegs;
}
public void setMaxPlannedEntryLegs(int maxPlannedEntryLegs) {
this.maxPlannedEntryLegs = maxPlannedEntryLegs;
}
public BigDecimal getMaxTotalPositionRatio() {
return maxTotalPositionRatio;
}
public void setMaxTotalPositionRatio(BigDecimal maxTotalPositionRatio) {
this.maxTotalPositionRatio = maxTotalPositionRatio;
}
public BigDecimal getMaxSingleLegRatio() {
return maxSingleLegRatio;
}
public void setMaxSingleLegRatio(BigDecimal maxSingleLegRatio) {
this.maxSingleLegRatio = maxSingleLegRatio;
}
}
public static class DataSource {
private String hashMode = "FULL_HASH_OR_SCHEMA_ROW_TIME_MISSING_SUMMARY";
public String getHashMode() {
return hashMode;
}
public void setHashMode(String hashMode) {
this.hashMode = hashMode;
public record PositionManager(BigDecimal maxSingleLegRatio, BigDecimal maxTotalPositionRatio) {
public PositionManager {
maxSingleLegRatio = maxSingleLegRatio == null ? BigDecimal.ONE : maxSingleLegRatio;
maxTotalPositionRatio = maxTotalPositionRatio == null ? BigDecimal.ONE : maxTotalPositionRatio;
}
}
}