Initial quant trader service baseline
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.domain.TraderReplayReport;
|
||||
import com.quantai.trader.infrastructure.entity.TraderReplayReportEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderReplayReportMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisReplayReportRepository implements ReplayReportRepository {
|
||||
|
||||
private final TraderReplayReportMapper mapper;
|
||||
|
||||
public MybatisReplayReportRepository(TraderReplayReportMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(TraderReplayReport report) {
|
||||
mapper.insert(toEntity(report));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TraderReplayReport> findByRunId(String runId) {
|
||||
TraderReplayReportEntity entity = mapper.selectOne(
|
||||
Wrappers.<TraderReplayReportEntity>lambdaQuery()
|
||||
.eq(TraderReplayReportEntity::getRunId, runId)
|
||||
.orderByDesc(TraderReplayReportEntity::getCreatedAt)
|
||||
.last("limit 1")
|
||||
);
|
||||
return Optional.ofNullable(entity).map(this::toDomain);
|
||||
}
|
||||
|
||||
private TraderReplayReportEntity toEntity(TraderReplayReport report) {
|
||||
TraderReplayReportEntity entity = new TraderReplayReportEntity();
|
||||
entity.setRunId(report.runId());
|
||||
entity.setReportId(report.reportId());
|
||||
entity.setSymbol(report.symbol());
|
||||
entity.setPlaybookId(report.playbookId());
|
||||
entity.setPlaybookVersion(report.playbookVersion());
|
||||
entity.setCandidateEvents(report.candidateEvents());
|
||||
entity.setMonthsCovered(report.monthsCovered());
|
||||
entity.setBaseNetReturnBps1x(report.baseNetReturnBps1x());
|
||||
entity.setLeveragedNetReturnBps10x(report.leveragedNetReturnBps10x());
|
||||
entity.setHoldoutReturnBps10x(report.holdoutReturnBps10x());
|
||||
entity.setStrictVsLooseJson(TraderPersistenceCodec.json(report.strictVsLoose()));
|
||||
entity.setFailureRisksJson(TraderPersistenceCodec.json(report.failureRisks()));
|
||||
entity.setConclusion(report.conclusion());
|
||||
entity.setReportPath(report.reportPath());
|
||||
entity.setCreatedAt(TraderPersistenceCodec.requiredLocal("report.createdAt", report.createdAt()));
|
||||
return entity;
|
||||
}
|
||||
|
||||
private TraderReplayReport toDomain(TraderReplayReportEntity entity) {
|
||||
return new TraderReplayReport(
|
||||
entity.getRunId(),
|
||||
entity.getReportId(),
|
||||
entity.getSymbol(),
|
||||
entity.getPlaybookId(),
|
||||
entity.getPlaybookVersion(),
|
||||
entity.getCandidateEvents(),
|
||||
entity.getMonthsCovered(),
|
||||
entity.getBaseNetReturnBps1x(),
|
||||
entity.getLeveragedNetReturnBps10x(),
|
||||
entity.getHoldoutReturnBps10x(),
|
||||
TraderPersistenceCodec.map(entity.getStrictVsLooseJson()),
|
||||
TraderPersistenceCodec.stringList(entity.getFailureRisksJson()),
|
||||
entity.getConclusion(),
|
||||
entity.getReportPath(),
|
||||
TraderPersistenceCodec.instant(entity.getCreatedAt())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.enums.ReplayRunStatus;
|
||||
import com.quantai.trader.infrastructure.entity.TraderReplayRunEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderReplayRunMapper;
|
||||
import com.quantai.trader.replay.ReplayRun;
|
||||
import com.quantai.trader.replay.ReplayRunConfig;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisReplayRunRepository implements ReplayRunRepository {
|
||||
|
||||
private final TraderReplayRunMapper mapper;
|
||||
|
||||
public MybatisReplayRunRepository(TraderReplayRunMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(ReplayRun run) {
|
||||
mapper.insert(toEntity(run));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ReplayRun run) {
|
||||
int updated = mapper.update(
|
||||
null,
|
||||
Wrappers.<TraderReplayRunEntity>lambdaUpdate()
|
||||
.set(TraderReplayRunEntity::getStatus, run.status().name())
|
||||
.set(TraderReplayRunEntity::getConfigJson, TraderPersistenceCodec.json(run.config()))
|
||||
.set(TraderReplayRunEntity::getStartedAt, TraderPersistenceCodec.local(run.startedAt()))
|
||||
.set(TraderReplayRunEntity::getFinishedAt, TraderPersistenceCodec.local(run.finishedAt()))
|
||||
.set(TraderReplayRunEntity::getFailureReason, run.failureReason())
|
||||
.eq(TraderReplayRunEntity::getRunId, run.runId())
|
||||
);
|
||||
if (updated == 0) {
|
||||
throw new IllegalStateException("replay run not found for update: " + run.runId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ReplayRun> findByRunId(String runId) {
|
||||
TraderReplayRunEntity entity = mapper.selectOne(
|
||||
Wrappers.<TraderReplayRunEntity>lambdaQuery()
|
||||
.eq(TraderReplayRunEntity::getRunId, runId)
|
||||
);
|
||||
return Optional.ofNullable(entity).map(this::toDomain);
|
||||
}
|
||||
|
||||
private TraderReplayRunEntity toEntity(ReplayRun run) {
|
||||
ReplayRunConfig config = run.config();
|
||||
TraderReplayRunEntity entity = new TraderReplayRunEntity();
|
||||
entity.setRunId(run.runId());
|
||||
entity.setRunMode("REPLAY");
|
||||
entity.setSymbol(config.symbol());
|
||||
entity.setPlaybookId(config.playbookId());
|
||||
entity.setPlaybookVersion(config.playbookVersion());
|
||||
entity.setPlaybookDefinitionHash(run.playbookDefinitionHash());
|
||||
entity.setDataFrom(TraderPersistenceCodec.local(config.from()));
|
||||
entity.setDataTo(TraderPersistenceCodec.local(config.to()));
|
||||
entity.setFeatureVersion(config.featureVersion());
|
||||
entity.setLabelVersion(config.labelVersion());
|
||||
entity.setDataSourceManifestJson(TraderPersistenceCodec.json(config.dataSources()));
|
||||
entity.setStatus(run.status().name());
|
||||
entity.setConfigJson(TraderPersistenceCodec.json(config));
|
||||
entity.setStartedAt(TraderPersistenceCodec.local(run.startedAt()));
|
||||
entity.setFinishedAt(TraderPersistenceCodec.local(run.finishedAt()));
|
||||
entity.setFailureReason(run.failureReason());
|
||||
entity.setCreatedAt(TraderPersistenceCodec.requiredLocal("run.createdAt", run.createdAt()));
|
||||
return entity;
|
||||
}
|
||||
|
||||
private ReplayRun toDomain(TraderReplayRunEntity entity) {
|
||||
return new ReplayRun(
|
||||
entity.getRunId(),
|
||||
ReplayRunStatus.valueOf(entity.getStatus()),
|
||||
TraderPersistenceCodec.replayRunConfig(entity.getConfigJson()),
|
||||
entity.getPlaybookDefinitionHash(),
|
||||
TraderPersistenceCodec.instant(entity.getCreatedAt()),
|
||||
TraderPersistenceCodec.instant(entity.getStartedAt()),
|
||||
TraderPersistenceCodec.instant(entity.getFinishedAt()),
|
||||
entity.getFailureReason()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.domain.TraderEvidence;
|
||||
import com.quantai.trader.infrastructure.entity.TraderEvidenceEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderEvidenceMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class MybatisTraderEvidenceRepository implements TraderEvidenceRepository {
|
||||
|
||||
private final TraderEvidenceMapper mapper;
|
||||
|
||||
public MybatisTraderEvidenceRepository(TraderEvidenceMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(TraderEvidence evidence) {
|
||||
TraderEvidenceEntity entity = new TraderEvidenceEntity();
|
||||
entity.setRunId(evidence.runId());
|
||||
entity.setCycleId(evidence.cycleId());
|
||||
entity.setEvidenceId(evidence.evidenceId());
|
||||
entity.setStage(evidence.stage());
|
||||
entity.setPass(evidence.pass());
|
||||
entity.setReason(evidence.reason());
|
||||
entity.setBlocker(evidence.blocker());
|
||||
entity.setEvidenceTime(TraderPersistenceCodec.local(evidence.evidenceTime()));
|
||||
entity.setDetailsJson(TraderPersistenceCodec.json(evidence.details()));
|
||||
entity.setCreatedAt(TraderPersistenceCodec.local(Instant.now()));
|
||||
mapper.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TraderEvidence> findByCycleId(String runId, String cycleId) {
|
||||
return mapper.selectList(
|
||||
Wrappers.<TraderEvidenceEntity>lambdaQuery()
|
||||
.eq(TraderEvidenceEntity::getRunId, runId)
|
||||
.eq(TraderEvidenceEntity::getCycleId, cycleId)
|
||||
.orderByAsc(TraderEvidenceEntity::getEvidenceTime)
|
||||
.orderByAsc(TraderEvidenceEntity::getId)
|
||||
).stream().map(this::toDomain).toList();
|
||||
}
|
||||
|
||||
private TraderEvidence toDomain(TraderEvidenceEntity entity) {
|
||||
return new TraderEvidence(
|
||||
entity.getRunId(),
|
||||
entity.getCycleId(),
|
||||
entity.getEvidenceId(),
|
||||
entity.getStage(),
|
||||
Boolean.TRUE.equals(entity.getPass()),
|
||||
entity.getReason(),
|
||||
entity.getBlocker(),
|
||||
TraderPersistenceCodec.instant(entity.getEvidenceTime()),
|
||||
TraderPersistenceCodec.map(entity.getDetailsJson())
|
||||
);
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.domain.TraderException;
|
||||
import com.quantai.trader.enums.TraderErrorCode;
|
||||
import com.quantai.trader.infrastructure.entity.TraderPlaybookDefinitionEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderPlaybookDefinitionMapper;
|
||||
import com.quantai.trader.playbook.TraderPlaybookDefinitionSnapshot;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class MybatisTraderPlaybookDefinitionRepository implements TraderPlaybookDefinitionRepository {
|
||||
|
||||
private final TraderPlaybookDefinitionMapper mapper;
|
||||
|
||||
public MybatisTraderPlaybookDefinitionRepository(TraderPlaybookDefinitionMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertPlaybookDefinitionIfAbsent(TraderPlaybookDefinitionSnapshot definition) {
|
||||
Optional<TraderPlaybookDefinitionSnapshot> existing = findPlaybookDefinition(
|
||||
definition.playbookId(),
|
||||
definition.playbookVersion()
|
||||
);
|
||||
if (existing.isPresent()) {
|
||||
if (!existing.get().definitionHashSha256().equals(definition.definitionHashSha256())) {
|
||||
throw new TraderException(
|
||||
TraderErrorCode.TRADER_PLAYBOOK_VERSION_CONFLICT,
|
||||
"playbook version already exists with another definition hash"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
mapper.insert(toEntity(definition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TraderPlaybookDefinitionSnapshot> findPlaybookDefinition(String playbookId, String playbookVersion) {
|
||||
TraderPlaybookDefinitionEntity entity = mapper.selectOne(
|
||||
Wrappers.<TraderPlaybookDefinitionEntity>lambdaQuery()
|
||||
.eq(TraderPlaybookDefinitionEntity::getPlaybookId, playbookId)
|
||||
.eq(TraderPlaybookDefinitionEntity::getPlaybookVersion, playbookVersion)
|
||||
);
|
||||
return Optional.ofNullable(entity).map(this::toDomain);
|
||||
}
|
||||
|
||||
private TraderPlaybookDefinitionEntity toEntity(TraderPlaybookDefinitionSnapshot definition) {
|
||||
TraderPlaybookDefinitionEntity entity = new TraderPlaybookDefinitionEntity();
|
||||
entity.setPlaybookId(definition.playbookId());
|
||||
entity.setPlaybookVersion(definition.playbookVersion());
|
||||
entity.setFamily(definition.family());
|
||||
entity.setVariant(definition.variant());
|
||||
entity.setSideMode(Objects.requireNonNull(definition.definition(), "playbook definition is required").sideMode());
|
||||
entity.setSourcePath(definition.sourcePath());
|
||||
entity.setDefinitionHashSha256(definition.definitionHashSha256());
|
||||
entity.setDefinitionJson(definition.definitionJson());
|
||||
entity.setLoadedAt(TraderPersistenceCodec.local(definition.loadedAt()));
|
||||
entity.setStatus(definition.status());
|
||||
entity.setCreatedAt(TraderPersistenceCodec.local(Instant.now()));
|
||||
return entity;
|
||||
}
|
||||
|
||||
private TraderPlaybookDefinitionSnapshot toDomain(TraderPlaybookDefinitionEntity entity) {
|
||||
String definitionJson = entity.getDefinitionJson();
|
||||
return new TraderPlaybookDefinitionSnapshot(
|
||||
entity.getPlaybookId(),
|
||||
entity.getPlaybookVersion(),
|
||||
entity.getFamily(),
|
||||
entity.getVariant(),
|
||||
entity.getSourcePath(),
|
||||
entity.getDefinitionHashSha256(),
|
||||
definitionJson,
|
||||
TraderPersistenceCodec.instant(entity.getLoadedAt()),
|
||||
entity.getStatus(),
|
||||
TraderPersistenceCodec.playbookDefinition(definitionJson)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.domain.TraderRiskDecision;
|
||||
import com.quantai.trader.enums.TraderActionType;
|
||||
import com.quantai.trader.infrastructure.entity.TraderRiskDecisionEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderRiskDecisionMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class MybatisTraderRiskDecisionRepository implements TraderRiskDecisionRepository {
|
||||
|
||||
private final TraderRiskDecisionMapper mapper;
|
||||
|
||||
public MybatisTraderRiskDecisionRepository(TraderRiskDecisionMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(TraderRiskDecision decision) {
|
||||
TraderRiskDecisionEntity entity = new TraderRiskDecisionEntity();
|
||||
entity.setRunId(decision.runId());
|
||||
entity.setCycleId(decision.cycleId());
|
||||
entity.setActionId(decision.actionId());
|
||||
entity.setAccountStateId(decision.accountStateId());
|
||||
entity.setActionType(decision.actionType().name());
|
||||
entity.setLeverageScreen(decision.leverageScreen());
|
||||
entity.setPlannedTotalPositionRatio(decision.plannedTotalPositionRatio());
|
||||
entity.setMaxLossBps(decision.maxLossBps());
|
||||
entity.setLiquidationBufferBps(decision.liquidationBufferBps());
|
||||
entity.setExpectedValueBps1x(decision.expectedValueBps1x());
|
||||
entity.setExpectedValueBps10x(decision.expectedValueBps10x());
|
||||
entity.setUncertainty(decision.uncertainty());
|
||||
entity.setOodScore(decision.oodScore());
|
||||
entity.setAllowAction(decision.allowAction());
|
||||
entity.setBlocker(decision.blocker());
|
||||
entity.setDecisionJson(TraderPersistenceCodec.json(decision.decision()));
|
||||
entity.setCreatedAt(TraderPersistenceCodec.requiredLocal("decision.createdAt", decision.createdAt()));
|
||||
mapper.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TraderRiskDecision> findByCycleId(String runId, String cycleId) {
|
||||
return mapper.selectList(
|
||||
Wrappers.<TraderRiskDecisionEntity>lambdaQuery()
|
||||
.eq(TraderRiskDecisionEntity::getRunId, runId)
|
||||
.eq(TraderRiskDecisionEntity::getCycleId, cycleId)
|
||||
.orderByAsc(TraderRiskDecisionEntity::getCreatedAt)
|
||||
.orderByAsc(TraderRiskDecisionEntity::getId)
|
||||
).stream().map(this::toDomain).toList();
|
||||
}
|
||||
|
||||
private TraderRiskDecision toDomain(TraderRiskDecisionEntity entity) {
|
||||
return new TraderRiskDecision(
|
||||
entity.getRunId(),
|
||||
entity.getCycleId(),
|
||||
entity.getActionId(),
|
||||
entity.getAccountStateId(),
|
||||
TraderActionType.valueOf(entity.getActionType()),
|
||||
entity.getLeverageScreen(),
|
||||
entity.getPlannedTotalPositionRatio(),
|
||||
entity.getMaxLossBps(),
|
||||
entity.getLiquidationBufferBps(),
|
||||
entity.getExpectedValueBps1x(),
|
||||
entity.getExpectedValueBps10x(),
|
||||
entity.getUncertainty(),
|
||||
entity.getOodScore(),
|
||||
Boolean.TRUE.equals(entity.getAllowAction()),
|
||||
entity.getBlocker(),
|
||||
TraderPersistenceCodec.map(entity.getDecisionJson()),
|
||||
TraderPersistenceCodec.instant(entity.getCreatedAt())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.quantai.trader.domain.TraderTrainingSample;
|
||||
import com.quantai.trader.infrastructure.entity.TraderTrainingSampleEntity;
|
||||
import com.quantai.trader.infrastructure.mapper.TraderTrainingSampleMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class MybatisTraderSampleRepository implements TraderSampleRepository {
|
||||
|
||||
private final TraderTrainingSampleMapper mapper;
|
||||
|
||||
public MybatisTraderSampleRepository(TraderTrainingSampleMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(TraderTrainingSample sample) {
|
||||
TraderTrainingSampleEntity entity = new TraderTrainingSampleEntity();
|
||||
entity.setRunId(sample.runId());
|
||||
entity.setCycleId(sample.cycleId());
|
||||
entity.setSampleId(sample.sampleId());
|
||||
entity.setActionId(sample.actionId());
|
||||
entity.setPositionId(sample.positionId());
|
||||
entity.setFeatureVersion(sample.featureVersion());
|
||||
entity.setLabelVersion(sample.labelVersion());
|
||||
entity.setSampleTime(TraderPersistenceCodec.local(sample.sampleTime()));
|
||||
entity.setFeaturesJson(TraderPersistenceCodec.json(sample.features()));
|
||||
entity.setLabelsJson(TraderPersistenceCodec.json(sample.labels()));
|
||||
entity.setNetReturnBps1x(sample.netReturnBps1x());
|
||||
entity.setNetReturnBps10x(sample.netReturnBps10x());
|
||||
entity.setProxyOnly(sample.proxyOnly());
|
||||
entity.setCreatedAt(TraderPersistenceCodec.local(Instant.now()));
|
||||
mapper.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TraderTrainingSample> findByRunId(String runId) {
|
||||
return mapper.selectList(
|
||||
Wrappers.<TraderTrainingSampleEntity>lambdaQuery()
|
||||
.eq(TraderTrainingSampleEntity::getRunId, runId)
|
||||
.orderByAsc(TraderTrainingSampleEntity::getSampleTime)
|
||||
.orderByAsc(TraderTrainingSampleEntity::getId)
|
||||
).stream().map(this::toDomain).toList();
|
||||
}
|
||||
|
||||
private TraderTrainingSample toDomain(TraderTrainingSampleEntity entity) {
|
||||
return new TraderTrainingSample(
|
||||
entity.getRunId(),
|
||||
entity.getCycleId(),
|
||||
entity.getSampleId(),
|
||||
entity.getActionId(),
|
||||
entity.getPositionId(),
|
||||
entity.getFeatureVersion(),
|
||||
entity.getLabelVersion(),
|
||||
TraderPersistenceCodec.instant(entity.getSampleTime()),
|
||||
TraderPersistenceCodec.map(entity.getFeaturesJson()),
|
||||
TraderPersistenceCodec.map(entity.getLabelsJson()),
|
||||
entity.getNetReturnBps1x(),
|
||||
entity.getNetReturnBps10x(),
|
||||
Boolean.TRUE.equals(entity.getProxyOnly())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.domain.TraderReplayReport;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ReplayReportRepository {
|
||||
|
||||
void insert(TraderReplayReport report);
|
||||
|
||||
Optional<TraderReplayReport> findByRunId(String runId);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.replay.ReplayRun;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ReplayRunRepository {
|
||||
|
||||
void insert(ReplayRun run);
|
||||
|
||||
void update(ReplayRun run);
|
||||
|
||||
Optional<ReplayRun> findByRunId(String runId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.domain.TraderEvidence;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TraderEvidenceRepository {
|
||||
|
||||
void insert(TraderEvidence evidence);
|
||||
|
||||
List<TraderEvidence> findByCycleId(String runId, String cycleId);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.quantai.trader.playbook.TraderPlaybookDefinition;
|
||||
import com.quantai.trader.replay.ReplayRunConfig;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
final class TraderPersistenceCodec {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().findAndRegisterModules();
|
||||
private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<>() {
|
||||
};
|
||||
private static final TypeReference<List<String>> STRING_LIST_TYPE = new TypeReference<>() {
|
||||
};
|
||||
|
||||
private TraderPersistenceCodec() {
|
||||
}
|
||||
|
||||
static String json(Object value) {
|
||||
try {
|
||||
return OBJECT_MAPPER.writeValueAsString(Objects.requireNonNull(value, "json value is required"));
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("failed to serialize trader persistence json", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, Object> map(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(requiredJson(json), MAP_TYPE);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("failed to deserialize trader persistence json map", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> stringList(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(requiredJson(json), STRING_LIST_TYPE);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("failed to deserialize trader persistence json list", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static ReplayRunConfig replayRunConfig(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(requiredJson(json), ReplayRunConfig.class);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("failed to deserialize replay run config", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static TraderPlaybookDefinition playbookDefinition(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(requiredJson(json), TraderPlaybookDefinition.class);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("failed to deserialize playbook definition", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static LocalDateTime local(Instant value) {
|
||||
return value == null ? null : LocalDateTime.ofInstant(value, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
static Instant instant(LocalDateTime value) {
|
||||
return value == null ? null : value.toInstant(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
static LocalDateTime requiredLocal(String fieldName, Instant value) {
|
||||
return LocalDateTime.ofInstant(Objects.requireNonNull(value, fieldName + " is required"), ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
private static String requiredJson(String json) {
|
||||
Objects.requireNonNull(json, "json text is required");
|
||||
String trimmed = json.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
throw new IllegalArgumentException("json text is blank");
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.playbook.TraderPlaybookDefinitionSnapshot;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface TraderPlaybookDefinitionRepository {
|
||||
|
||||
void insertPlaybookDefinitionIfAbsent(TraderPlaybookDefinitionSnapshot definition);
|
||||
|
||||
Optional<TraderPlaybookDefinitionSnapshot> findPlaybookDefinition(String playbookId, String playbookVersion);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.domain.TraderRiskDecision;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TraderRiskDecisionRepository {
|
||||
|
||||
void insert(TraderRiskDecision decision);
|
||||
|
||||
List<TraderRiskDecision> findByCycleId(String runId, String cycleId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.quantai.trader.persistence;
|
||||
|
||||
import com.quantai.trader.domain.TraderTrainingSample;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TraderSampleRepository {
|
||||
|
||||
void insert(TraderTrainingSample sample);
|
||||
|
||||
List<TraderTrainingSample> findByRunId(String runId);
|
||||
}
|
||||
Reference in New Issue
Block a user