Compare commits
131 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aa61465ce0 | |||
| bccefed35e | |||
| d610ecb57c | |||
| c852ad49cf | |||
| 3fbb5ea2bf | |||
| a45961928e | |||
| 736951526b | |||
| ed137c2574 | |||
| b694a101d1 | |||
| 14ced733f2 | |||
| 6475ecd3b0 | |||
| 29929d76d3 | |||
| 6772a86081 | |||
| 6ff40c8ea3 | |||
| 6f252162ef | |||
| ee4ae5583d | |||
| d7c106f292 | |||
| eb3a33f124 | |||
| 528a1b4425 | |||
| 3483f84044 | |||
| ebbd42e4e0 | |||
| 445715ded3 | |||
| e926a7af75 | |||
| 344cdba9f1 | |||
| b3fb3a9eff | |||
| fbb35c5296 | |||
| 8565556b3f | |||
| 5d02bdf5e6 | |||
| 5359300f8a | |||
| b97db19824 | |||
| 9dc2323b9a | |||
| 91ece33518 | |||
| 1a235a171d | |||
| d897438675 | |||
| 5728a11fbd | |||
| bcb3b2ba6d | |||
| 59bd7af33d | |||
| 266adede77 | |||
| 7ff226d622 | |||
| 9df28ecaa2 | |||
| 2701f7bba5 | |||
| 09ad1f64ab | |||
| 3c42eb402b | |||
| 0f4e589cf1 | |||
| add83a2a8f | |||
| 7e0d3ad5b0 | |||
| 5bf24d4f66 | |||
| 9c01c60f7c | |||
| 0c37bfa13c | |||
| db25edfd87 | |||
| 902dcd1dc8 | |||
| ea9614be13 | |||
| 3c22798e08 | |||
| 157f17ec52 | |||
| c67e116953 | |||
| f698880aaa | |||
| a9d92dcfcc | |||
| 89d5842505 | |||
| b0c9776601 | |||
| 5589a0432b | |||
| f9a0ba3690 | |||
| 2a46dd5503 | |||
| c56dd7e35d | |||
| d2e9bbf9f0 | |||
| 6348550149 | |||
| 26b163eab9 | |||
| 1c192ecdea | |||
| 82e18a9a22 | |||
| 6d9937c590 | |||
| ef6f9c74f6 | |||
| 24ec410f3d | |||
| 024122d310 | |||
| c6f269e30a | |||
| 97447a551f | |||
| fc0d341d15 | |||
| 688ee3350d | |||
| f40da64a05 | |||
| 475950be36 | |||
| 27a56e65b7 | |||
| a9986fbc4c | |||
| ee14f5fbe4 | |||
| 3f45fbc36e | |||
| 87949f42b5 | |||
| 4eb23a41ca | |||
| 6db27fd634 | |||
| a3fe301308 | |||
| bcc9b76212 | |||
| 7172de3623 | |||
| 6582ffc02a | |||
| f8ff3a2c46 | |||
| ecc7deed08 | |||
| ee0787683b | |||
| f8d93de299 | |||
| 7db7f74713 | |||
| fbb56400af | |||
| 744e9d6a7a | |||
| 521d1c0b3d | |||
| d49e45b308 | |||
| 49dc382a39 | |||
| 15b9840204 | |||
| 534582972d | |||
| 890ed68a0f | |||
| 92efa934a2 | |||
| cc001fa263 | |||
| 606664404b | |||
| a7f9b27a55 | |||
| 34991eca2d | |||
| d833d386d0 | |||
| daec1a0e1b | |||
| a9b8f46187 | |||
| eb48b7eb07 | |||
| 187cdf99c0 | |||
| 21da79cb46 | |||
| 49637f1b02 | |||
| e15e4c6e20 | |||
| 6e666844f0 | |||
| 3f6c21c86e | |||
| 6fb43fb411 | |||
| 5d89c6ad02 | |||
| 1d90580854 | |||
| c25e3bee7a | |||
| 6e20a924db | |||
| 780ccee1fe | |||
| 129e2ec2d7 | |||
| 4cd1cab466 | |||
| be043a85e3 | |||
| 1c46d7b558 | |||
| 7f0c9b9a27 | |||
| 42d45e85fb | |||
| e7d1069222 | |||
| a274ef448a |
+126
-68
@@ -1,17 +1,33 @@
|
|||||||
name: Validators (Pull Requests Only)
|
name: Validators (Pushes and Pull Requests)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
# Phase 3: Validator pipeline
|
# Validator pipeline. Independent validation jobs run in parallel.
|
||||||
# Main branch push validation moved to merge-to-main.yml
|
|
||||||
# This workflow runs validators only on PRs for feedback
|
concurrency:
|
||||||
|
group: quantengine-ci-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
validate-core:
|
validate-core:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: quantengine_ci
|
||||||
|
POSTGRES_PASSWORD: quantengine_ci
|
||||||
|
POSTGRES_DB: quantenginedb
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 5s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 10
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
@@ -32,38 +48,39 @@ jobs:
|
|||||||
- name: Setup Python Environment
|
- name: Setup Python Environment
|
||||||
run: |
|
run: |
|
||||||
# 순수 Python 패키지만 설치 (numpy/pandas 제외 — ARMv7l 휠 없음)
|
# 순수 Python 패키지만 설치 (numpy/pandas 제외 — ARMv7l 휠 없음)
|
||||||
VENV_BASE=$HOME/python_venv
|
PYTHON_DEPS="$HOME/python_deps/$(md5sum tools/validate_specs.py | cut -d' ' -f1)"
|
||||||
REQ_HASH=$(md5sum tools/validate_specs.py 2>/dev/null | cut -d' ' -f1 || echo "default")
|
mkdir -p "$PYTHON_DEPS"
|
||||||
VENV="$VENV_BASE/$REQ_HASH"
|
/usr/bin/python3 --version
|
||||||
|
/usr/bin/python3 -m pip --version
|
||||||
|
/usr/bin/python3 -m pip install --disable-pip-version-check --quiet \
|
||||||
|
--target "$PYTHON_DEPS" requests pyyaml openpyxl pytest "psycopg[binary]"
|
||||||
|
export PYTHONPATH="$PYTHON_DEPS:${PYTHONPATH:-}"
|
||||||
|
echo "PYTHONPATH=$PYTHON_DEPS:${PYTHONPATH:-}" >> "$GITHUB_ENV"
|
||||||
|
/usr/bin/python3 -c 'import requests, yaml, openpyxl, pytest, psycopg; print("Python dependencies: PASS")'
|
||||||
|
|
||||||
if [ ! -f "$VENV/bin/python" ]; then
|
- name: Apply Database Migrations (CI Postgres service)
|
||||||
echo "=== venv 신규 생성: $REQ_HASH ==="
|
env:
|
||||||
mkdir -p "$VENV_BASE"
|
PGPASSWORD: quantengine_ci
|
||||||
/usr/bin/python3 -m venv "$VENV"
|
PGHOST: postgres
|
||||||
|
PGPORT: 5432
|
||||||
|
run: |
|
||||||
|
# QE-M2-01 등 스키마 존재만 확인하는 게이트는 실제 Postgres에 대해 재검증한다
|
||||||
|
# (2026-07-12: WBS 게이트가 마이그레이션 SQL만으로 스키마를 주장하지 않도록,
|
||||||
|
# ci.yml 전용 postgres 서비스 컨테이너에 실제 DbUp 마이그레이션을 순서대로 적용).
|
||||||
|
which psql || (sudo apt-get update -qq && sudo apt-get install -y -qq postgresql-client)
|
||||||
|
for f in $(ls src/dotnet/QuantEngine.Infrastructure/Migrations/V*.sql | sort -V); do
|
||||||
|
echo "=== Applying $f ==="
|
||||||
|
psql -U quantengine_ci -d quantenginedb -v ON_ERROR_STOP=1 -f "$f"
|
||||||
|
done
|
||||||
|
echo "QE_WBS_PG_DSN=host=postgres port=5432 dbname=quantenginedb user=quantengine_ci password=quantengine_ci options='-c search_path=quantengine'" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
# venv 내 pip 확인 및 복구
|
- name: Setup .NET SDK
|
||||||
if [ ! -f "$VENV/bin/pip" ]; then
|
uses: actions/setup-dotnet@v4
|
||||||
echo "pip missing in venv, installing via get-pip.py..."
|
with:
|
||||||
curl -sS https://bootstrap.pypa.io/pip/3.8/get-pip.py -o get-pip.py
|
dotnet-version: 10.0.x
|
||||||
"$VENV/bin/python" get-pip.py --quiet
|
|
||||||
rm get-pip.py
|
|
||||||
fi
|
|
||||||
|
|
||||||
"$VENV/bin/pip" install --upgrade pip --quiet
|
- name: "[CRITICAL] Run .NET Unit Tests (Warnings as Errors)"
|
||||||
"$VENV/bin/pip" install requests pyyaml openpyxl --quiet
|
run: dotnet test src/dotnet/QuantEngine.Core.Tests/QuantEngine.Core.Tests.csproj -c Release --nologo -p:TreatWarningsAsErrors=true
|
||||||
|
|
||||||
# 오래된 venv 정리 (최근 2개만 유지)
|
|
||||||
ls -dt "$VENV_BASE"/*/ 2>/dev/null | tail -n +3 | xargs rm -rf 2>/dev/null || true
|
|
||||||
else
|
|
||||||
echo "=== venv 캐시 히트: $("$VENV/bin/python" --version 2>&1) ==="
|
|
||||||
"$VENV/bin/python" - <<'PY'
|
|
||||||
import importlib
|
|
||||||
for mod in ("requests", "yaml", "openpyxl"):
|
|
||||||
importlib.import_module(mod)
|
|
||||||
print("venv dependency import check: PASS")
|
|
||||||
PY
|
|
||||||
fi
|
|
||||||
echo "$VENV/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Install Node Dependencies
|
- name: Install Node Dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -86,7 +103,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "=== npm install (최초 or lock 변경) ==="
|
echo "=== npm install (최초 or lock 변경) ==="
|
||||||
npm install --quiet
|
npm ci --quiet
|
||||||
# 캐시 저장
|
# 캐시 저장
|
||||||
mkdir -p "$CACHE_DIR"
|
mkdir -p "$CACHE_DIR"
|
||||||
cp -r node_modules "$CACHE_DIR/node_modules"
|
cp -r node_modules "$CACHE_DIR/node_modules"
|
||||||
@@ -120,6 +137,67 @@ jobs:
|
|||||||
- name: Validate Platform Transition WBS
|
- name: Validate Platform Transition WBS
|
||||||
run: python3 tools/validate_platform_transition_wbs_v1.py
|
run: python3 tools/validate_platform_transition_wbs_v1.py
|
||||||
|
|
||||||
|
- name: Validate Market Time Series Schema
|
||||||
|
run: python3 tools/validate_market_time_series_schema_v1.py
|
||||||
|
|
||||||
|
- name: Generate DONE WBS Verdicts
|
||||||
|
run: |
|
||||||
|
# DONE 작업 중 CI(ubuntu-latest, 위 postgres 서비스 컨테이너)에서 온디맨드로 재검증
|
||||||
|
# 가능한 것만 나열한다. 실제 KIS API/라이브 앱이 전제인 나머지 DONE 작업은
|
||||||
|
# spec/60의 execution.mode: not_ci_reproducible 로 별도 표시되어
|
||||||
|
# validate_quant_engine_wbs_v1.py 가 verdict 부재를 FAIL로 취급하지 않는다.
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
root = Path.cwd()
|
||||||
|
spec = yaml.safe_load((root / "spec" / "60_quant_engine_wbs.yaml").read_text(encoding="utf-8"))
|
||||||
|
tasks = spec.get("tasks") or {}
|
||||||
|
for task_id, task in tasks.items():
|
||||||
|
if task.get("status") != "DONE":
|
||||||
|
continue
|
||||||
|
mode = ((task.get("execution") or {}).get("mode"))
|
||||||
|
if mode in {"not_ci_reproducible", "manual_user_action"}:
|
||||||
|
continue
|
||||||
|
subprocess.run(["python3", "tools/verify_wbs_task_v1.py", "--task", task_id], check=True, cwd=root)
|
||||||
|
PY
|
||||||
|
|
||||||
|
- name: Validate Quant Engine WBS
|
||||||
|
run: python3 tools/validate_quant_engine_wbs_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Migration Roadmap
|
||||||
|
run: python3 tools/validate_dotnet_migration_roadmap_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Migration Execution Plan
|
||||||
|
run: python3 tools/validate_dotnet_migration_execution_plan_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Parity Contract
|
||||||
|
run: python3 tools/validate_dotnet_parity_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Provenance Contract
|
||||||
|
run: python3 tools/validate_dotnet_provenance_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Scheduler Contract
|
||||||
|
run: python3 tools/validate_dotnet_scheduler_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Normalization Contract
|
||||||
|
run: python3 tools/validate_dotnet_normalization_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Idempotency Contract
|
||||||
|
run: python3 tools/validate_dotnet_idempotency_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet CICD Chain Contract
|
||||||
|
run: python3 tools/validate_dotnet_cicd_chain_contract_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Domain Parity Backlog
|
||||||
|
run: python3 tools/validate_dotnet_domain_parity_backlog_v1.py
|
||||||
|
|
||||||
|
- name: Validate Dotnet Read Model Contract
|
||||||
|
run: python3 tools/validate_dotnet_read_model_contract_v1.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Build Calibration Priority Backlog
|
- name: Build Calibration Priority Backlog
|
||||||
run: python3 tools/build_calibration_priority_v1.py
|
run: python3 tools/build_calibration_priority_v1.py
|
||||||
|
|
||||||
@@ -168,18 +246,19 @@ jobs:
|
|||||||
- name: Ensure Temp Directory and Mock Packet
|
- name: Ensure Temp Directory and Mock Packet
|
||||||
run: |
|
run: |
|
||||||
mkdir -p Temp
|
mkdir -p Temp
|
||||||
|
python3 -c 'import json; json.dump({"order_blueprint_json":{},"cash_recovery_plan_json":{},"per_ticker":[{"ticker":"DATA_MISSING","gate":"DATA_MISSING"}],"meta":{"formulas_run":[],"source_file":"GatherTradingData.json"}},open("Temp/computed_harness_v1.json","w"),ensure_ascii=False,indent=2)'
|
||||||
if [ ! -f Temp/final_decision_packet_active.json ]; then
|
if [ ! -f Temp/final_decision_packet_active.json ]; then
|
||||||
echo '{"formula_id":"FINAL_DECISION_PACKET_V2","meta":{"generated_at":"2026-06-29T00:00:00Z"},"canonical_metrics":{},"portfolio_snapshot":{},"order_table":[]}' > Temp/final_decision_packet_active.json
|
python3 -c 'import json; json.dump({"formula_id":"FINAL_DECISION_PACKET_V2","meta":{"generated_at":"2026-06-29T00:00:00Z"},"canonical_metrics":{"total_asset_krw":None},"portfolio_snapshot":{},"order_table":[],"pass_100":{"gate":"DATA_MISSING","score_0_100":None},"execution_readiness":{"gate":"DATA_MISSING","min_axis_score":None},"prediction":{"match_rate_pct":None}},open("Temp/final_decision_packet_active.json","w"),ensure_ascii=False,indent=2)'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Validate Replay Live Separation
|
- name: Validate Replay Live Separation
|
||||||
run: python3 tools/validate_replay_live_separation_v1.py
|
run: python3 tools/validate_replay_live_separation_v1.py
|
||||||
|
|
||||||
- name: Render Final Decision Packet V4
|
- name: Render Final Decision Packet V4
|
||||||
run: dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -- packet-v4 --packet=Temp/final_decision_packet_active.json --out=Temp/final_decision_packet_v4.json
|
run: dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -p:TreatWarningsAsErrors=true -- packet-v4 --packet=Temp/final_decision_packet_active.json --out=Temp/final_decision_packet_v4.json
|
||||||
|
|
||||||
- name: Render Operational Report
|
- name: Render Operational Report
|
||||||
run: dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -- report --packet=Temp/final_decision_packet_active.json --out=Temp/operational_report.json
|
run: dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -p:TreatWarningsAsErrors=true -- report --packet=Temp/final_decision_packet_active.json --out=Temp/operational_report.json
|
||||||
|
|
||||||
- name: Validate Report Packet Sync
|
- name: Validate Report Packet Sync
|
||||||
run: python3 tools/validate_report_packet_sync_v1.py --packet Temp/final_decision_packet_active.json --report Temp/operational_report.json | tee Temp/validate_report_packet_sync_v1.json
|
run: python3 tools/validate_report_packet_sync_v1.py --packet Temp/final_decision_packet_active.json --report Temp/operational_report.json | tee Temp/validate_report_packet_sync_v1.json
|
||||||
@@ -197,7 +276,7 @@ jobs:
|
|||||||
run: python3 tools/validate_postgresql_history_contract_v1.py
|
run: python3 tools/validate_postgresql_history_contract_v1.py
|
||||||
|
|
||||||
- name: Package Operational Report Artifacts
|
- name: Package Operational Report Artifacts
|
||||||
run: tar -czf Temp/operational-report-artifacts.tar.gz Temp/operational_report.json Temp/operational_report.md Temp/missing_data_inventory_v1.json Temp/report_section_completeness.json Temp/operational_alpha_calibration_v2.json Temp/validate_operational_alpha_calibration_v2.json Temp/operational_t20_outcome_ledger_v1.json Temp/live_data_activation_gate_v1.json Temp/replay_live_separation_v1.json Temp/validate_report_packet_sync_v1.json Temp/json_generator_outputs_v1.json Temp/proposal_evaluation_history.json Temp/performance_readiness_replay_bridge_v1.json Temp/postgresql_history_schema_v1.sql Temp/postgresql_history_schema_v1.json Temp/postgresql_history_contract_v1.json
|
run: tar -czf Temp/operational-report-artifacts.tar.gz Temp/operational_report.json Temp/missing_data_inventory_v1.json Temp/report_section_completeness.json Temp/operational_alpha_calibration_v2.json Temp/validate_operational_alpha_calibration_v2.json Temp/operational_t20_outcome_ledger_v1.json Temp/live_data_activation_gate_v1.json Temp/replay_live_separation_v1.json Temp/validate_report_packet_sync_v1.json Temp/json_generator_outputs_v1.json Temp/proposal_evaluation_history.json Temp/performance_readiness_replay_bridge_v1.json Temp/postgresql_history_schema_v1.sql Temp/postgresql_history_schema_v1.json Temp/postgresql_history_contract_v1.json
|
||||||
|
|
||||||
- name: Upload Operational Report Artifacts
|
- name: Upload Operational Report Artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -213,8 +292,6 @@ jobs:
|
|||||||
|
|
||||||
validate-ui-and-storage:
|
validate-ui-and-storage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: validate-core
|
|
||||||
if: github.event_name != 'push'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
@@ -224,47 +301,28 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Python Environment
|
- name: Setup Python Environment
|
||||||
run: |
|
run: |
|
||||||
VENV_BASE=$HOME/python_venv
|
PYTHON_DEPS="$HOME/python_deps/$(md5sum tools/validate_snapshot_admin_web_v1.py | cut -d' ' -f1)"
|
||||||
REQ_HASH=$(md5sum tools/validate_snapshot_admin_web_v1.py 2>/dev/null | cut -d' ' -f1 || echo "default")
|
mkdir -p "$PYTHON_DEPS"
|
||||||
VENV="$VENV_BASE/$REQ_HASH"
|
/usr/bin/python3 --version
|
||||||
|
/usr/bin/python3 -m pip --version
|
||||||
if [ ! -f "$VENV/bin/python" ]; then
|
/usr/bin/python3 -m pip install --disable-pip-version-check --quiet \
|
||||||
echo "=== venv 신규 생성: $REQ_HASH ==="
|
--target "$PYTHON_DEPS" requests pyyaml openpyxl pytest
|
||||||
mkdir -p "$VENV_BASE"
|
export PYTHONPATH="$PYTHON_DEPS:${PYTHONPATH:-}"
|
||||||
/usr/bin/python3 -m venv "$VENV"
|
echo "PYTHONPATH=$PYTHON_DEPS:${PYTHONPATH:-}" >> "$GITHUB_ENV"
|
||||||
|
/usr/bin/python3 -c 'import requests, yaml, openpyxl, pytest; print("Python dependencies: PASS")'
|
||||||
if [ ! -f "$VENV/bin/pip" ]; then
|
|
||||||
echo "pip missing in venv, installing via get-pip.py..."
|
|
||||||
curl -sS https://bootstrap.pypa.io/pip/3.8/get-pip.py -o get-pip.py
|
|
||||||
"$VENV/bin/python" get-pip.py --quiet
|
|
||||||
rm get-pip.py
|
|
||||||
fi
|
|
||||||
|
|
||||||
"$VENV/bin/pip" install --upgrade pip --quiet
|
|
||||||
"$VENV/bin/pip" install requests pyyaml openpyxl --quiet
|
|
||||||
else
|
|
||||||
echo "=== venv 캐시 히트: $("$VENV/bin/python" --version 2>&1) ==="
|
|
||||||
fi
|
|
||||||
echo "$VENV/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Validate Snapshot Admin Web UI
|
- name: Validate Snapshot Admin Web UI
|
||||||
if: needs.validate-core.result == 'success'
|
|
||||||
run: python3 tools/validate_snapshot_admin_web_v1.py
|
run: python3 tools/validate_snapshot_admin_web_v1.py
|
||||||
|
|
||||||
- name: Validate Storage Backend Contracts
|
- name: Validate Storage Backend Contracts
|
||||||
if: needs.validate-core.result == 'success'
|
|
||||||
run: python3 -m pytest tests/unit/test_storage_backend_v1.py tests/unit/test_validate_kis_api_credentials_v1.py tests/unit/test_qualitative_sell_strategy_store_v1.py tests/unit/test_kis_api_client_v1.py tests/unit/test_snapshot_admin_store_v1.py tests/unit/test_snapshot_admin_web_v1.py -q
|
run: python3 -m pytest tests/unit/test_storage_backend_v1.py tests/unit/test_validate_kis_api_credentials_v1.py tests/unit/test_qualitative_sell_strategy_store_v1.py tests/unit/test_kis_api_client_v1.py tests/unit/test_snapshot_admin_store_v1.py tests/unit/test_snapshot_admin_web_v1.py -q
|
||||||
|
|
||||||
- name: Notify PR Result
|
- name: Notify PR Result
|
||||||
if: always() && github.event_name == 'pull_request'
|
if: always() && github.event_name == 'pull_request'
|
||||||
env:
|
env:
|
||||||
CORE_RESULT: ${{ needs.validate-core.result }}
|
|
||||||
STAGE_RESULT: ${{ job.status }}
|
STAGE_RESULT: ${{ job.status }}
|
||||||
run: |
|
run: |
|
||||||
STATUS="$STAGE_RESULT"
|
STATUS="$STAGE_RESULT"
|
||||||
if [ "$CORE_RESULT" != "success" ]; then
|
|
||||||
STATUS="failure"
|
|
||||||
fi
|
|
||||||
PR_NUM="${{ github.event.pull_request.number }}"
|
PR_NUM="${{ github.event.pull_request.number }}"
|
||||||
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
if [ "$STATUS" = "success" ]; then
|
if [ "$STATUS" = "success" ]; then
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name: CI Workflow Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- ".gitea/workflows/ci.yml"
|
||||||
|
- "tools/validate_gitea_ci_workflow_lint_v1.py"
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- ".gitea/workflows/ci.yml"
|
||||||
|
- "tools/validate_gitea_ci_workflow_lint_v1.py"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-ci-workflow-lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Python Environment
|
||||||
|
run: |
|
||||||
|
/usr/bin/python3 --version
|
||||||
|
/usr/bin/python3 -m pip --version
|
||||||
|
PYTHON_DEPS="$HOME/python_deps/$(md5sum tools/validate_gitea_ci_workflow_lint_v1.py | cut -d' ' -f1)"
|
||||||
|
mkdir -p "$PYTHON_DEPS"
|
||||||
|
/usr/bin/python3 -m pip install --disable-pip-version-check --quiet \
|
||||||
|
--target "$PYTHON_DEPS" pyyaml
|
||||||
|
export PYTHONPATH="$PYTHON_DEPS:${PYTHONPATH:-}"
|
||||||
|
echo "PYTHONPATH=$PYTHON_DEPS:${PYTHONPATH:-}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Lint CI Workflow Contract
|
||||||
|
run: python3 tools/validate_gitea_ci_workflow_lint_v1.py --workflow .gitea/workflows/ci.yml
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
name: Deploy to Production
|
name: Deploy to Production
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Prepare Release"]
|
||||||
|
types: [completed]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
release:
|
release:
|
||||||
@@ -9,7 +12,7 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: deploy-prod-main
|
group: deploy-prod-${{ github.event.workflow_run.head_sha || github.sha }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@@ -22,6 +25,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy to Production
|
name: Deploy to Production
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
outputs:
|
outputs:
|
||||||
@@ -88,6 +92,74 @@ jobs:
|
|||||||
echo "✓ Artifact: $ARTIFACT"
|
echo "✓ Artifact: $ARTIFACT"
|
||||||
echo "✓ Download URL: $DOWNLOAD_URL"
|
echo "✓ Download URL: $DOWNLOAD_URL"
|
||||||
|
|
||||||
|
- name: Validate Release Chain
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_run" ]; then
|
||||||
|
EXPECTED_SHA="${{ github.event.workflow_run.head_sha }}"
|
||||||
|
RELEASE_TAG="${{ steps.fetch.outputs.tag }}"
|
||||||
|
RELEASE_SHA="${RELEASE_TAG##*.}"
|
||||||
|
EXPECTED_SHA_SHORT="${EXPECTED_SHA:0:${#RELEASE_SHA}}"
|
||||||
|
|
||||||
|
if [ "$EXPECTED_SHA_SHORT" != "$RELEASE_SHA" ]; then
|
||||||
|
echo "ERROR: Release SHA does not match upstream workflow SHA"
|
||||||
|
echo "Expected: $EXPECTED_SHA"
|
||||||
|
echo "Expected short: $EXPECTED_SHA_SHORT"
|
||||||
|
echo "Release: $RELEASE_SHA"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ Release chain verified: $EXPECTED_SHA_SHORT"
|
||||||
|
else
|
||||||
|
echo "✓ Workflow dispatch mode — release chain verification skipped"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Validate Upstream CI Success
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
REPO: ${{ env.REPO }}
|
||||||
|
EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||||
|
run: |
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
token = os.environ["GITEA_TOKEN"]
|
||||||
|
repo = os.environ["REPO"]
|
||||||
|
expected_sha = os.environ.get("EXPECTED_SHA", "")
|
||||||
|
if not expected_sha:
|
||||||
|
print("✓ Workflow dispatch mode — upstream CI validation skipped")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
matched_ci = None
|
||||||
|
for page in range(1, 6):
|
||||||
|
url = f"https://gitea.taxbaik.com/api/v1/repos/{repo}/actions/runs?limit=50&page={page}"
|
||||||
|
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||||
|
payload = json.load(resp)
|
||||||
|
|
||||||
|
for run in payload.get("workflow_runs", []):
|
||||||
|
path = str(run.get("path") or "")
|
||||||
|
if "ci.yml@" not in path:
|
||||||
|
continue
|
||||||
|
if run.get("status") != "completed" or run.get("conclusion") != "success":
|
||||||
|
continue
|
||||||
|
actual_sha = str(run.get("head_sha") or "")
|
||||||
|
if actual_sha != expected_sha:
|
||||||
|
continue
|
||||||
|
matched_ci = run
|
||||||
|
break
|
||||||
|
if matched_ci:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not matched_ci:
|
||||||
|
print("ERROR: No successful ci.yml run found for the release SHA")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"✓ Upstream CI verified: {expected_sha} (run {matched_ci.get('id')})")
|
||||||
|
PY
|
||||||
|
|
||||||
- name: Download Release Artifact
|
- name: Download Release Artifact
|
||||||
run: |
|
run: |
|
||||||
ARTIFACT="${{ steps.fetch.outputs.artifact }}"
|
ARTIFACT="${{ steps.fetch.outputs.artifact }}"
|
||||||
@@ -204,12 +276,8 @@ jobs:
|
|||||||
echo "ERROR: QuantEngine.Web.dll not found"
|
echo "ERROR: QuantEngine.Web.dll not found"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$DEPLOY_DIR/appsettings.Production.json" ]; then
|
|
||||||
echo "ERROR: appsettings.Production.json not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ DLL verified"
|
echo "✓ DLL verified"
|
||||||
echo "✓ Config verified"
|
echo "✓ Runtime configuration is managed outside the release artifact"
|
||||||
|
|
||||||
# 3. Update Symlink
|
# 3. Update Symlink
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
name: KIS Data Collection Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 0 * * 1-5"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Validate mock credentials
|
||||||
|
env:
|
||||||
|
KIS_APP_Key_TEST: ${{ vars.KIS_APP_KEY_TEST }}
|
||||||
|
KIS_APP_Secret_TEST: ${{ vars.KIS_APP_SECRET_TEST }}
|
||||||
|
KIS_APP_Key: ${{ vars.KIS_APP_KEY }}
|
||||||
|
KIS_APP_Secret: ${{ vars.KIS_APP_SECRET }}
|
||||||
|
run: python3 tools/validate_kis_api_credentials_v1.py --account mock --ticker 005930 --dry-run
|
||||||
|
- name: Validate .NET PostgreSQL JSON cutover
|
||||||
|
run: python3 tools/validate_dotnet_postgresql_json_cutover_v1.py
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
name: Prepare Release
|
name: Prepare Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Validators (Pushes and Pull Requests)"]
|
||||||
|
types: [completed]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
@@ -11,11 +14,28 @@ on:
|
|||||||
env:
|
env:
|
||||||
DOTNET_VERSION: '10.0.x'
|
DOTNET_VERSION: '10.0.x'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: prepare-release-${{ github.event.workflow_run.head_sha || github.sha }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
upstream-gate:
|
||||||
|
name: Upstream Success Gate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Fail Fast on Failed Validator Chain
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_run" ] && [ "${{ github.event.workflow_run.conclusion }}" != "success" ]; then
|
||||||
|
echo "ERROR: Validators workflow did not succeed; release preparation is blocked."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
build-and-release:
|
build-and-release:
|
||||||
name: Build & Create Release
|
name: Build & Create Release
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
|
needs: upstream-gate
|
||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.metadata.outputs.version }}
|
version: ${{ steps.metadata.outputs.version }}
|
||||||
commit: ${{ steps.metadata.outputs.commit }}
|
commit: ${{ steps.metadata.outputs.commit }}
|
||||||
@@ -92,6 +112,10 @@ jobs:
|
|||||||
--no-restore \
|
--no-restore \
|
||||||
--no-build
|
--no-build
|
||||||
|
|
||||||
|
- name: Write Version Text
|
||||||
|
run: |
|
||||||
|
echo "${{ steps.metadata.outputs.version }}" > ./publish/version.txt
|
||||||
|
|
||||||
- name: Write Production Config
|
- name: Write Production Config
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ./publish
|
mkdir -p ./publish
|
||||||
@@ -187,7 +211,7 @@ jobs:
|
|||||||
name: Release Notification
|
name: Release Notification
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
needs: build-and-release
|
needs: [upstream-gate, build-and-release]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Notify Release Ready
|
- name: Notify Release Ready
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
name: Qualitative Sell Strategy Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "15 0 * * 1-5"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
DEPS="$RUNNER_TEMP/quantengine_sell_deps"
|
||||||
|
python3 -m pip install --disable-pip-version-check --quiet --target "$DEPS" pyyaml
|
||||||
|
echo "PYTHONPATH=$DEPS:${PYTHONPATH:-}" >> "$GITHUB_ENV"
|
||||||
|
- name: Validate mock credentials
|
||||||
|
env:
|
||||||
|
KIS_APP_Key_TEST: ${{ vars.KIS_APP_KEY_TEST }}
|
||||||
|
KIS_APP_Secret_TEST: ${{ vars.KIS_APP_SECRET_TEST }}
|
||||||
|
run: python3 tools/validate_kis_api_credentials_v1.py --account mock --ticker 005930 --dry-run
|
||||||
|
- name: Validate qualitative sell pipeline
|
||||||
|
run: python3 tools/validate_qualitative_sell_strategy_pipeline_v1.py
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Snapshot Admin Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- "src/quant_engine/snapshot_admin_*.py"
|
||||||
|
- "tools/validate_snapshot_admin_*.py"
|
||||||
|
- "tests/unit/test_snapshot_admin_*.py"
|
||||||
|
- ".gitea/workflows/snapshot_admin.yml"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
PYTHON_DEPS="$RUNNER_TEMP/quantengine_snapshot_admin_deps"
|
||||||
|
python3 -m pip install --disable-pip-version-check --quiet --target "$PYTHON_DEPS" pyyaml pytest
|
||||||
|
echo "PYTHONPATH=$PYTHON_DEPS:${PYTHONPATH:-}" >> "$GITHUB_ENV"
|
||||||
|
- name: Validate snapshot admin workflow
|
||||||
|
run: python3 tools/validate_snapshot_admin_workflow_v1.py
|
||||||
|
- name: Run snapshot admin tests
|
||||||
|
run: python3 -m pytest tests/unit/test_snapshot_admin_store_v1.py tests/unit/test_snapshot_admin_web_v1.py -q
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# 은퇴자산포트폴리오 투자 에이전트 운영 지침
|
# 은퇴자산포트폴리오 투자 에이전트 운영 지침
|
||||||
|
|
||||||
|
## QuantEngine 운영 설정 권위
|
||||||
|
- `ConnectionStrings__DefaultConnection`은 운영 설정에서 관리한다.
|
||||||
|
- 저장소 코드, DbUp migration, CI artifact는 운영 계정 비밀번호를 생성하거나 덮어쓰지 않는다. 단, 명시된 운영 설정 복원 작업은 예외로 한다.
|
||||||
|
- 배포/검증 하네스는 설정값을 읽기만 하며, 값 자체를 로그·증빙·커밋에 기록하지 않는다.
|
||||||
|
- 설정 변경은 애플리케이션 배포와 분리된 운영 설정 변경으로 취급한다. 설정 복원 시에는 Git 이력의 마지막 권위값만 사용한다.
|
||||||
|
|
||||||
## 0. 최우선 원칙
|
## 0. 최우선 원칙
|
||||||
- 이 파일은 운영 인덱스다. 상세 규칙은 `governance/rules/*.yaml`와 `spec/*.yaml`를 우선한다.
|
- 이 파일은 운영 인덱스다. 상세 규칙은 `governance/rules/*.yaml`와 `spec/*.yaml`를 우선한다.
|
||||||
- 가격, 수량, TP/SL, 점수는 오직 `spec/13_formula_registry.yaml`와 하네스 산출값만 사용한다.
|
- 가격, 수량, TP/SL, 점수는 오직 `spec/13_formula_registry.yaml`와 하네스 산출값만 사용한다.
|
||||||
@@ -77,17 +83,40 @@
|
|||||||
- `tools/validate_platform_transition_wbs_v1.py`: `.gs → Python` and `xlsx → sqlite` WBS validator.
|
- `tools/validate_platform_transition_wbs_v1.py`: `.gs → Python` and `xlsx → sqlite` WBS validator.
|
||||||
- `tools/validate_qualitative_sell_strategy_pipeline_v1.py`: qualitative sell validator.
|
- `tools/validate_qualitative_sell_strategy_pipeline_v1.py`: qualitative sell validator.
|
||||||
- `tools/validate_gitea_secrets_contract_v1.py`: Gitea secrets validator.
|
- `tools/validate_gitea_secrets_contract_v1.py`: Gitea secrets validator.
|
||||||
|
- `tools/validate_gitea_ci_workflow_lint_v1.py`: CI workflow lint validator for recurring service-binding mistakes.
|
||||||
- `tools/validate_snapshot_admin_web_v1.py`: snapshot admin smoke validator.
|
- `tools/validate_snapshot_admin_web_v1.py`: snapshot admin smoke validator.
|
||||||
- `tests/parity/test_price_qty_parity_v1.py`: price/qty parity.
|
- `tests/parity/test_price_qty_parity_v1.py`: price/qty parity.
|
||||||
- `tests/parity/test_score_parity_v1.py`: timing score parity.
|
- `tests/parity/test_score_parity_v1.py`: timing score parity.
|
||||||
- `tests/parity/test_routing_gate_parity_v1.py`: routing gate parity.
|
- `tests/parity/test_routing_gate_parity_v1.py`: routing gate parity.
|
||||||
- `.gitea/workflows/qualitative_sell_strategy.yml`: qualitative sell strategy workflow.
|
- `.gitea/workflows/qualitative_sell_strategy.yml`: qualitative sell strategy workflow.
|
||||||
- `.gitea/workflows/snapshot_admin.yml`: snapshot admin workflow and scheduled validation.
|
- `.gitea/workflows/snapshot_admin.yml`: snapshot admin workflow and scheduled validation.
|
||||||
|
- `.gitea/workflows/ci_lint.yml`: CI workflow lint gate for `.gitea/workflows/ci.yml`.
|
||||||
- `docs/CLOUD_SERVER_SETUP.md`: 클라우드 서버(hz-prod-01, 178.104.200.7) 설정 하네스 가이드. 시놀로지 → 클라우드 마이그레이션 매핑 포함.
|
- `docs/CLOUD_SERVER_SETUP.md`: 클라우드 서버(hz-prod-01, 178.104.200.7) 설정 하네스 가이드. 시놀로지 → 클라우드 마이그레이션 매핑 포함.
|
||||||
- `docs/GITEA_SECRETS_SETUP.md`: Gitea secrets setup and verification guide.
|
- `docs/GITEA_SECRETS_SETUP.md`: Gitea secrets setup and verification guide.
|
||||||
- `docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md`: `GatherTradingData.xlsx` 보조 자산 런북.
|
- `docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md`: `GatherTradingData.xlsx` 보조 자산 런북.
|
||||||
- `docs/ROADMAP_WBS.md`: `.gs → Python` 및 `xlsx → sqlite` WBS.
|
- `docs/ROADMAP_WBS.md`: `.gs → Python` 및 `xlsx → sqlite` WBS.
|
||||||
- `docs/ROADMAP_WBS.md`의 WBS-8.2: `run_kis_data_collection_v1.py` → `validate_platform_transition_wbs_v1.py` → `validate_snapshot_admin_web_v1.py`.
|
- `docs/ROADMAP_WBS.md`의 WBS-8.2: `run_kis_data_collection_v1.py` → `validate_platform_transition_wbs_v1.py` → `validate_snapshot_admin_web_v1.py`.
|
||||||
|
- `docs/WBS_10_DOTNET_MIGRATION_ROADMAP.yaml`: `.NET 엔진 고도화` 상세 WBS와 각 WBS별 성공 데이터 가이드.
|
||||||
|
- `docs/WBS_10_DOTNET_MIGRATION_INVENTORY.yaml`: WBS-10 전환 우선순위용 실행 경로 인벤토리.
|
||||||
|
- `docs/WBS_10_DOTNET_MIGRATION_EXECUTION_PLAN.yaml`: WBS-10 착수용 실행 분해 계획.
|
||||||
|
- `docs/WBS_10_DOTNET_PARITY_CONTRACT.yaml`: WBS-10 핵심 계산기 parity 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_PROVENANCE_CONTRACT.yaml`: WBS-10 provenance payload 표준 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_SCHEDULER_CONTRACT.yaml`: WBS-10 scheduler state machine 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_NORMALIZATION_CONTRACT.yaml`: WBS-10 normalization/read model 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_IDEMPOTENCY_CONTRACT.yaml`: WBS-10 idempotency/lock 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_CICD_CHAIN_CONTRACT.yaml`: WBS-10 CI/CD 순차 게이트 계약.
|
||||||
|
- `docs/WBS_10_DOTNET_DOMAIN_PARITY_BACKLOG.yaml`: WBS-10 domain parity backlog contract.
|
||||||
|
- `docs/WBS_10_DOTNET_READ_MODEL_CONTRACT.yaml`: WBS-10 read model contract.
|
||||||
|
- `tools/validate_dotnet_migration_roadmap_v1.py`: WBS-10 상세 로드맵 YAML validator.
|
||||||
|
- `tools/validate_dotnet_migration_execution_plan_v1.py`: WBS-10 실행 분해 계획 validator.
|
||||||
|
- `tools/validate_dotnet_parity_contract_v1.py`: WBS-10 parity 계약 validator.
|
||||||
|
- `tools/validate_dotnet_provenance_contract_v1.py`: WBS-10 provenance 계약 validator.
|
||||||
|
- `tools/validate_dotnet_scheduler_contract_v1.py`: WBS-10 scheduler 계약 validator.
|
||||||
|
- `tools/validate_dotnet_normalization_contract_v1.py`: WBS-10 normalization 계약 validator.
|
||||||
|
- `tools/validate_dotnet_idempotency_contract_v1.py`: WBS-10 idempotency 계약 validator.
|
||||||
|
- `tools/validate_dotnet_cicd_chain_contract_v1.py`: WBS-10 CI/CD chain 계약 validator.
|
||||||
|
- `tools/validate_dotnet_domain_parity_backlog_v1.py`: WBS-10 domain parity backlog validator.
|
||||||
|
- `tools/validate_dotnet_read_model_contract_v1.py`: WBS-10 read model validator.
|
||||||
- `Temp/snapshot_admin_approval_packet_v1.json`: snapshot admin approval packet export.
|
- `Temp/snapshot_admin_approval_packet_v1.json`: snapshot admin approval packet export.
|
||||||
- `Temp/snapshot_admin_approval_packet_v1.md`: snapshot admin approval packet summary.
|
- `Temp/snapshot_admin_approval_packet_v1.md`: snapshot admin approval packet summary.
|
||||||
- `Temp/`: 실행 결과와 캐시. 라우팅 대상은 아니며 runtime consumer만 읽는다.
|
- `Temp/`: 실행 결과와 캐시. 라우팅 대상은 아니며 runtime consumer만 읽는다.
|
||||||
@@ -136,28 +165,31 @@
|
|||||||
- 클라우드 서버(hz-prod-01)는 `/usr/bin/python3`를 사용하므로 `.gitea/workflows/ci.yml`은 `python3` 유지
|
- 클라우드 서버(hz-prod-01)는 `/usr/bin/python3`를 사용하므로 `.gitea/workflows/ci.yml`은 `python3` 유지
|
||||||
- **임시 파일 관리**: 개발/디버깅 목적의 모든 휘발성 임시 파일 및 로그는 반드시 `Temp/` 디렉토리 하위에서만 생성해야 하며, 루트나 다른 패키지 경로에 임시 파일을 만드는 것은 금지한다. 불가피하게 생성할 경우 반드시 접두사/접미사 규칙(`debug_*`, `tmp_*`, `mock_*`, `*_temp.*`)을 준수하여 `.gitignore`에 필터링되도록 한다.
|
- **임시 파일 관리**: 개발/디버깅 목적의 모든 휘발성 임시 파일 및 로그는 반드시 `Temp/` 디렉토리 하위에서만 생성해야 하며, 루트나 다른 패키지 경로에 임시 파일을 만드는 것은 금지한다. 불가피하게 생성할 경우 반드시 접두사/접미사 규칙(`debug_*`, `tmp_*`, `mock_*`, `*_temp.*`)을 준수하여 `.gitignore`에 필터링되도록 한다.
|
||||||
|
|
||||||
## 5b. Blazor & API-First 개발 규칙 (TaxBaik 참조 모델 적용)
|
## 5b. Razor Pages 개발 규칙 (Tabler 참조 모델 적용)
|
||||||
- **핵심 아키텍처 원칙**: Blazor WASM 개발은 **패턴화(Pattern), 템플릿화(Template), 컴포넌트화(Component), MVVM 패턴, API-First 아키텍처**를 최우선 가치로 준수한다.
|
- **핵심 아키텍처 원칙**: 어드민 웹 개발은 ASP.NET Core Razor Pages 패턴 및 단일 책임 원칙(SRP)을 따르는 비즈니스 서비스 분리를 최우선 가치로 준수한다.
|
||||||
- **렌더 모드 표준**: Blazor **Interactive WebAssembly** 를 기본 렌더 모드로 한다. InteractiveServer 는 사용하지 않으며, UI 컴포넌트는 **MudBlazor** 로 통일한다 (Fluent UI 는 폐기).
|
- **렌더 모드 표준**: 순수 서버 사이드 렌더링(SSR) 및 Razor 뷰 엔진을 활용하며, UI 디자인은 Tabler CSS/JS 프레임워크 표준에 맞추어 구현한다.
|
||||||
- **API-First 아키텍처 (MVVM + FastEndpoints)**:
|
- **보안 및 CSRF 방어**: 모든 POST/CUD 액션 처리 시 안티포저리 토큰(`@Html.AntiForgeryToken()`) 유효성 검증을 필수로 수행하여 CSRF 공격을 전면 차단한다.
|
||||||
- **백엔드(Server)**: 기존 컨트롤러 구조를 전면 배제하고, REPR(Request-Endpoint-Response) 패턴을 보장하는 **FastEndpoints** 프레임워크를 기반으로 백엔드 API 엔드포인트를 구현하여 단일 책임 원칙(SRP)을 준수한다.
|
|
||||||
- **프론트엔드(Client)**: Blazor WASM 클라이언트는 Razor 컴포넌트(View)와 상태/검증/로직을 갖춘 DTO 및 StateService(ViewModel) 구조의 **MVVM 패턴**을 지향하여 화면 바인딩 정합성을 극대화한다. UI 계층은 비즈니스 로직이나 DB에 직접 결합되지 않고, `IXxxBrowserClient` 또는 추상화된 HttpClient API 클라이언트를 통해서만 백엔드 API와 통신한다.
|
|
||||||
- **이중 토큰 인증 패턴**: Access Token(15분) 및 Refresh Token(7일) 이중 토큰 패턴을 적용하며, HttpClient 요청 시 401 Unauthorized를 가로채어 자동으로 localStorage의 Refresh Token으로 토큰을 자동 갱신 및 재시도하는 `TokenRefreshHandler` (DelegatingHandler) 구조를 준수한다.
|
|
||||||
- **실시간 알림 (SignalR)**: 실시간 알림 기능은 상태를 직접 동기화하는 용도가 아닌 단순 Event-driven 브로드캐스트 알림으로 설계하며, 클라이언트는 알림 수신 후 API 호출을 통해 최종 데이터를 검증 및 동기화한다.
|
|
||||||
- **UI/UX 구현**:
|
- **UI/UX 구현**:
|
||||||
- MudBlazor 컴포넌트(MudDataGrid Dense + Virtualize)를 사용하여 고밀도(행높이 32px 수준) 및 대량 데이터 성능을 보장한다.
|
- Tabler 기반 테이블 뷰와 모달 대화상자(Modal Dialog) 패턴을 일관되게 활용하여 CRUD 및 데이터 수정 저장을 플래시 없이 유연하게 연동한다.
|
||||||
- CRUD 생성 및 수정 작업 시 화면 플래시를 제거하기 위해 MudDialog 모달 대화상자 패턴을 사용하며, 삭제 작업에는 `ConfirmDialog` 등을 이용해 명시적 사용자 확인을 거친다.
|
|
||||||
- 상태 및 등급 구분에는 시각적 가시성을 위한 Status Color Chips(Success, Warning, Error)를 적용한다.
|
- 상태 및 등급 구분에는 시각적 가시성을 위한 Status Color Chips(Success, Warning, Error)를 적용한다.
|
||||||
- **DTO 및 유효성 검증 규칙**: API 입력 모델 및 데이터 전송 객체(DTO) 유효성 검증 시 데이터 어노테이션(DTO Annotation) 방식을 기본적으로 사용하되, 복잡한 비즈니스 조건부 유효성 검증이나 데이터베이스 연동 유효성 검사 등 어노테이션만으로 부족한 영역은 **FluentValidation**을 상호 보완적으로 적용하여 유효성 규칙을 중앙 집중식으로 엄격히 관리한다.
|
|
||||||
- **엔지니어링 표준화 지침**:
|
- **엔지니어링 표준화 지침**:
|
||||||
- **표준화 & 컴포넌트화**: UI 요소와 재사용 가능한 비즈니스 코어는 컴포넌트 단위로 구조화하며, 파편화된 개별 커스텀 스타일이나 인라인 데이터 변환을 배제하고 MudBlazor 및 표준 헬퍼 클래스를 공통 활용한다.
|
- **표준화 & 컴포넌트화**: 공통 레이아웃(`_AdminLayout.cshtml`)과 부분 뷰(Partial View)를 적극적으로 분리/재사용하고, 파편화된 개별 스타일을 지양하여 Tabler 및 표준 유틸리티 클래스를 공통 활용한다.
|
||||||
- **정규화 & 비정규화**: DB 스키마 설계 시에는 정규화 모델을 준수하여 중복과 파편화를 방지하고, 화면 조회 성능이나 BFF 통합 렌더링을 위한 데이터 구조화 단계에서만 안전하게 비정규화된 DTO/뷰 모델을 빌드하여 전송한다.
|
|
||||||
- **데이터 정합성 & 리팩토링**: 모든 비즈니스 도메인의 상태 전이는 ACID 트랜잭션 단위 및 인프라 레이어의 일관성 제어 규칙을 보장하며, 복잡도가 과한 하드코딩 영역은 SRP(단일 책임 원칙) 및 인터페이스 기반 구조로 점진적 리팩토링한다.
|
- **데이터 정합성 & 리팩토링**: 모든 비즈니스 도메인의 상태 전이는 ACID 트랜잭션 단위 및 인프라 레이어의 일관성 제어 규칙을 보장하며, 복잡도가 과한 하드코딩 영역은 SRP(단일 책임 원칙) 및 인터페이스 기반 구조로 점진적 리팩토링한다.
|
||||||
- **파편화 & 바이브 코드 방지**: provenance(근거) 없는 암묵적 룰이나 감에 의존한 구조(Vibe Code)의 무분별한 탑재를 금지하고, 모든 상태 및 에러 코드는 코드북에 엄격히 등록된 정방형 정규 값만 할당한다.
|
- **파편화 & 바이브 코드 방지**: provenance(근거) 없는 암묵적 룰이나 감에 의존한 구조(Vibe Code)의 무분별한 탑재를 금지하고, 모든 상태 및 에러 코드는 코드북에 엄격히 등록된 정방형 정규 값만 할당한다.
|
||||||
- **하네스 & 테스트 안정성**: 모든 패치는 `Temp/` 및 하네스 테스트 스위트의 빌드 및 통과 로그를 통해 데이터로 증빙한다. 하네스 실패 시 빌드 승격을 전면 차단한다.
|
- **하네스 & 테스트 안정성**: 모든 패치는 `Temp/` 및 하네스 테스트 스위트의 빌드 및 통과 로그를 통해 데이터로 증빙한다. 하네스 실패 시 빌드 승격을 전면 차단한다.
|
||||||
- **비즈니스 로직 단순화**: 다차원 중첩 조건이나 연쇄 트리거를 제거하고 선형 구조(Waterfall, Sequence)의 단순 프로세스 플로우로 구현하여 추적 가능성을 극대화한다.
|
- **비즈니스 로직 단순화**: 다차원 중첩 조건이나 연쇄 트리거를 제거하고 선형 구조(Waterfall, Sequence)의 단순 프로세스 플로우로 구현하여 추적 가능성을 극대화한다.
|
||||||
- **코드 및 다국어 규칙**: 모든 관리자 UI 레이블, 폼, 오류 메시지는 한국어로 작성하며, 소스 코드 주석 및 내부 예외 메시지는 영어 작성을 허용한다. 클래스, 메서드, 프로퍼티는 `PascalCase`를 사용하고 비동기 메서드에는 `Async` 접미사를 지정한다.
|
- **코드 및 다국어 규칙**: 모든 관리자 UI 레이블, 폼, 오류 메시지는 한국어로 작성하며, 소스 코드 주석 및 내부 예외 메시지는 영어 작성을 허용한다. 클래스, 메서드, 프로퍼티는 `PascalCase`를 사용하고 비동기 메서드에는 `Async` 접미사를 지정한다.
|
||||||
|
|
||||||
|
## 5c. 퀀트 엔진 엔지니어링 철학 및 구현 원칙 (Operational Philosophy)
|
||||||
|
- **SOLID & 컴포넌트화(Componentization) & 정공법**: 모든 C#/.NET 코드 작성 시 SOLID 원칙을 준수한다. 각 모듈은 단일 책임 원칙(SRP)을 가지며, 인터페이스와 비즈니스 서비스 레이어로 철저히 **컴포넌트화**하여 결합도를 낮추는 **정공법** 아키텍처를 고수한다.
|
||||||
|
- **데이터 정합성 & 정규화/역정규화**: 데이터 모델링 시 정합성 유지를 위해 관계형 데이터베이스의 **정규화**를 최우선으로 하며, 성능 최적화가 필수적인 어드민 조회 그리드용 데이터 전달(BFF/DTO) 시에만 제한적으로 안전하게 **역정규화**된 뷰 모델을 허용한다.
|
||||||
|
- **과유불급 & 프로세스 단순화**: 복잡한 중첩 트리거와 과도한 추상화(Over-engineering)를 경계하는 **과유불급** 원칙을 따른다. 비즈니스 흐름은 최대한 선형적이고 명시적인 프로세스로 단순화하여 디버깅 및 추적 가시성을 극대화한다.
|
||||||
|
- **바이브코딩(Vibe Coding) & 할루시네이션(Hallucination) 방지**: 퀀트 엔진 개발 시 LLM이나 인간 개발자의 주관적인 감(Vibe)과 추측에 의존한 임의의 상수 지정 또는 팩터 수식 재구성을 엄격히 금지한다. 모든 공식 및 의사결정 규칙은 `spec/*.yaml` 명세에 따라 철저히 **데이터 기반(Data-Driven)**으로 유도하고 테스트 코드로 실증한다.
|
||||||
|
- **단순 추측이 아닌 데이터 기반 예측**: 퀀트 모델의 모든 예측(알파, 리스크, 목표 가격 등)은 개발자의 직관이나 단순 추측이 아닌, 과거 시계열 통계 데이터 및 재현 가능한 백필 데이터를 근거로 설계한다. 모델 성능 평가는 E2E 테스트 하네스에서 산출된 정합성 결과와 백테스팅 실증 로그 등 철저히 데이터에 기반하여 의사결정을 수행한다.
|
||||||
|
- **최적 알고리즘 & 게임이론**: 슬리피지 최소화 및 레짐(시장국면) 적응형 포지션 사이징 처리 시, 호가 갭 스프레드 분석과 동적 캘리브레이션을 포함하는 **최적 알고리즘**을 활용하며, 시장 참여자 간의 호가 유동성 경쟁 속에서 불리한 주문이 실행되지 않도록 체결 우선순위 Waterfall 모델(게임이론적 리스크 가드)을 장착한다.
|
||||||
|
- **현장감 & 기술 부채**: 빌드 경고 및 사용되지 않는 쓰레기 코드를 즉각적으로 해결하여 **기술 부채**의 누적을 원천 차단한다. 실제 OpenAPI 응답 레이턴시, 스레드 병목 현상 및 어드민 DB 현황 조회 시 발생하는 트래픽을 로컬 및 E2E 실증 데이터로 직접 모니터링하여 **현장감** 있는 실전 최적화를 구현한다.
|
||||||
|
- **패턴화 & 표준화 & 구조화**: 명명 규칙, 디자인 패턴(예: Repository, Factory 등) 및 뷰 엔진 레이아웃은 합의된 양식을 엄격히 준수하도록 **표준화**하고, 핵심 퀀트 리팩토링 단계마다 빌드 무결성을 보증하도록 아키텍처를 **구조화**한다.
|
||||||
|
|
||||||
## 6. 검증 규칙
|
## 6. 검증 규칙
|
||||||
- `python tools/validate_specs.py`
|
- `python tools/validate_specs.py`
|
||||||
- `python tools/validate_golden_coverage_100.py`
|
- `python tools/validate_golden_coverage_100.py`
|
||||||
|
|||||||
@@ -688,3 +688,6 @@ See `docs/GITEA_ACTIONS_API_GUIDE.md` for complete API reference.
|
|||||||
- **Newtonsoft.Json**: Known high-severity vulnerability (GHSA-5crp-9r3c-p9vr); update or replace when feasible
|
- **Newtonsoft.Json**: Known high-severity vulnerability (GHSA-5crp-9r3c-p9vr); update or replace when feasible
|
||||||
- **Release Authority**: Python gates (`full-gate`, `prepare-upload-zip`) remain authority; .NET Admin fully operational as of 2026-07-11
|
- **Release Authority**: Python gates (`full-gate`, `prepare-upload-zip`) remain authority; .NET Admin fully operational as of 2026-07-11
|
||||||
- **Testing Requirement**: All code changes must pass local testing with SSH tunnel to remote DB before deployment (see "Local Development & Testing" above)
|
- **Testing Requirement**: All code changes must pass local testing with SSH tunnel to remote DB before deployment (see "Local Development & Testing" above)
|
||||||
|
- **DBML Schema Sync (2026-07-12)**: DbUp 마이그레이션(`src/dotnet/QuantEngine.Infrastructure/Migrations/V*.sql`)으로 관리되는 모든 테이블은 **반드시 `docs/db/quantengine.dbml`에도 동기화**되어야 하며, 개발 시 스키마 참조는 이 DBML 파일을 기준으로 한다. 새 마이그레이션 추가 시 같은 커밋에서 DBML 갱신 필수.
|
||||||
|
- **Diagrams**: 상태전이/플로우차트/시퀀스 다이어그램은 Mermaid로 `docs/diagrams/`에 작성해 코딩 참조로 활용 (수집 파이프라인: `docs/diagrams/collection-pipeline.md`)
|
||||||
|
- **WBS Evidence Gate (2026-07-12)**: 퀀트 엔진 로드맵/WBS는 `spec/60_quant_engine_wbs.yaml`(기계 판정)로 관리. 작업 완료는 `npm run verify:task -- <TASK_ID>` 게이트 PASS로만 인정 (BE=PG쿼리/로그/JSON, FE=Playwright+스크린샷). 전체 게이트: `npm run verify:wbs`
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Report Guide (보고서 지침)
|
||||||
|
|
||||||
|
본 문서는 은퇴자산 포트폴리오 투자 에이전트의 보고 및 작업 완료 기준을 정의합니다.
|
||||||
|
|
||||||
|
## 기본 완료 조건 (Default Completion Harness)
|
||||||
|
모든 작업은 아래의 4가지 요소가 모두 충족되어 검증을 통과해야 완료로 판정합니다.
|
||||||
|
|
||||||
|
1. **YAML 계약/공식**: 계약, 공식 및 거버넌스 파일(`yaml`)의 원본 권위가 변경 사항에 맞게 최신화되어야 합니다.
|
||||||
|
2. **코드 구현**: `code` 구현이 `src/` 또는 `tools/`에 명확히 반영되어야 합니다.
|
||||||
|
3. **데이터 실체**: 수집 및 계산 결과가 담긴 데이터 실체(`data artifact` 또는 `data/artifact`)가 디렉토리에 정상적으로 생성되고 확인되어야 합니다.
|
||||||
|
4. **검증 증빙**: 재현 가능한 테스트 실행 및 검증 명령의 결과 파일 또는 터미널 출력이 `validation evidence`(`검증 증빙`)로 기록되어야 합니다.
|
||||||
|
|
||||||
|
이러한 완료 프로세스는 `completion harness`를 통해 엄격하게 통제됩니다.
|
||||||
+126
-14
@@ -24,10 +24,10 @@
|
|||||||
|
|
||||||
모든 작업은 아래 7가지 증빙이 함께 충족되고, 하네스 검증을 통과할 때만 완료로 본다.
|
모든 작업은 아래 7가지 증빙이 함께 충족되고, 하네스 검증을 통과할 때만 완료로 본다.
|
||||||
|
|
||||||
- **MudBlazor 9 UI 표준 준수**: 모든 UI 컴포넌트 개발 시 **MudBlazor 9.0.0 버전** 표준 및 Interactive WebAssembly를 렌더 모드로 강제한다. Fluent UI 및 구버전(8.x 이하) 요소와의 혼용을 엄격히 배제한다.
|
- **Tabler UI 표준 준수**: 모든 UI 개발 시 **Tabler CSS/JS** 표준 및 ASP.NET Core Razor Pages를 기본 렌더 모드로 한다. 타 프레임워크와의 혼용을 엄격히 배제한다.
|
||||||
- **컴파일/빌드 완료**: 빌드 시 컴파일 에러 및 **컴파일 경고(Warning)가 0개**여야 한다.
|
- **컴파일/빌드 완료**: 빌드 시 컴파일 에러 및 **컴파일 경고(Warning)가 0개**여야 한다.
|
||||||
- **DTO 및 유효성 검증 규칙**: API 입력 모델 및 DTO 유효성 검증 시 **데이터 어노테이션(Data Annotation) 방식을 기본적으로 사용**하되, 복잡한 비즈니스 조건부 유효성 검증 등 어노테이션만으로 부족한 영역은 **FluentValidation을 상호 보완적으로 적용**하여 규칙을 중앙 집중식으로 엄격히 관리해야 한다.
|
- **DTO 및 유효성 검증 규칙**: API 입력 모델 및 DTO 유효성 검증 시 **데이터 어노테이션(Data Annotation) 방식을 기본적으로 사용**하되, 복잡한 비즈니스 조건부 유효성 검증 등 어노테이션만으로 부족한 영역은 **FluentValidation을 상호 보완적으로 적용**하여 규칙을 중앙 집중식으로 엄격히 관리해야 한다.
|
||||||
- **MVVM 패턴**: Blazor 화면 바인딩 정합성을 극대화하기 위해 Razor 컴포넌트(View)와 상태/검증/로직을 갖춘 DTO 및 StateService(ViewModel) 구조의 **MVVM 패턴을 철저히 지향**해야 한다.
|
- **Razor Pages 패턴**: ASP.NET Core Razor Pages 표준 아키텍처에 맞게, `.cshtml` 뷰와 비즈니스 서비스 계층을 완벽히 분리하고 안티포저리 토큰(CSRF 방어) 유효성 검증을 필수로 수행해야 한다.
|
||||||
- **Playwright E2E 하네스 검증**: 사용자 입장에서 시나리오에 따라 서비스를 직접 호출(Playwright 실행)하여, 실제 반환된 DOM 값과 화면 캡처 결과가 예측한 데이터/화면과 완벽히 일치하여 데이터로 증빙되어야 성공으로 판정한다.
|
- **Playwright E2E 하네스 검증**: 사용자 입장에서 시나리오에 따라 서비스를 직접 호출(Playwright 실행)하여, 실제 반환된 DOM 값과 화면 캡처 결과가 예측한 데이터/화면과 완벽히 일치하여 데이터로 증빙되어야 성공으로 판정한다.
|
||||||
- **병렬 테스트 및 인증 키 공유**: CI 테스트 및 로컬 테스트 수행 시 선후관계(순차 종속성)로 인해 병목이 생기지 않도록, 인증 완료 후의 인증 키(Cookie, Bearer Token 등)를 테스트 간 상호 공유 및 재사용(storageState 등)하도록 구성하여 **반드시 병렬(Parallel) 작업**으로 실행되어야 한다.
|
- **병렬 테스트 및 인증 키 공유**: CI 테스트 및 로컬 테스트 수행 시 선후관계(순차 종속성)로 인해 병목이 생기지 않도록, 인증 완료 후의 인증 키(Cookie, Bearer Token 등)를 테스트 간 상호 공유 및 재사용(storageState 등)하도록 구성하여 **반드시 병렬(Parallel) 작업**으로 실행되어야 한다.
|
||||||
- `YAML` 증빙: 관련 contract/spec/governance 문서가 일관되게 갱신되어야 한다.
|
- `YAML` 증빙: 관련 contract/spec/governance 문서가 일관되게 갱신되어야 한다.
|
||||||
@@ -170,7 +170,7 @@ Phase 10 ░░░░░░░░░░░░░░░░░░░░ C#/.NET
|
|||||||
| **P5 완전 자동화** | ~2026-12 | CI/CD + Gitea, 자율 실행 | 수동 개입 0회/주 |
|
| **P5 완전 자동화** | ~2026-12 | CI/CD + Gitea, 자율 실행 | 수동 개입 0회/주 |
|
||||||
| **P6 비기계적 매도전략** | 2026-06 완료 | 5팩터 confluence 엔진, KIS 조회연동, SQLite 자체평가 | WBS-6 본문 하네스 PASS (잔류위험은 P7에서 해소) |
|
| **P6 비기계적 매도전략** | 2026-06 완료 | 5팩터 confluence 엔진, KIS 조회연동, SQLite 자체평가 | WBS-6 본문 하네스 PASS (잔류위험은 P7에서 해소) |
|
||||||
| **P7 보완·고도화** | ~2026-08 | 캘리브레이션 실증 전환, GAS 마이그레이션 완결, deprecated 정리, E2E 통합테스트 | WBS-7.1~7.8 하네스 전부 PASS |
|
| **P7 보완·고도화** | ~2026-08 | 캘리브레이션 실증 전환, GAS 마이그레이션 완결, deprecated 정리, E2E 통합테스트 | WBS-7.1~7.8 하네스 전부 PASS |
|
||||||
| **P10 .NET 엔진 고도화** | ~2026-12 | C# Domain Parity, 테스트 100+건, Application 서비스, Blazor 대시보드, 보안 경화 | `dotnet test` 전체 PASS + parity JSON gate PASS |
|
| **P10 .NET 엔진 고도화** | ~2026-12 | C# Domain Parity, 테스트 100+건, Application 서비스, Razor Pages 어드민 대시보드, 보안 경화 | `dotnet test` 전체 PASS + parity JSON gate PASS |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1097,6 +1097,56 @@ LLM이 런타임에 이런 stale spec을 사실로 읽으면 할루시네이션
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### WBS-7.12 작업 관리 수동 즉시 실행 경로 교정
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 어드민 페이지(Operations)의 "즉시 실행" 기능이 동작하도록 explicit 폼 핸들러 액션 매핑 적용 |
|
||||||
|
| **담당 파일** | `src/dotnet/QuantEngine.Web/Pages/Admin/Operations/Index.cshtml` |
|
||||||
|
| **상태** | ✅ 완료 (2026-07-12) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### WBS-7.13 Hangfire 작업 수행 시간(TotalDuration) 연동
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 최근 작업 실행 목록에서 소요 시간이 0.0s로 고정 출력되던 버그를 SucceededJobDto.TotalDuration 및 StartedAt 연산으로 수정 |
|
||||||
|
| **담당 파일** | `src/dotnet/QuantEngine.Web/Pages/Admin/Operations/Index.cshtml.cs` |
|
||||||
|
| **상태** | ✅ 완료 (2026-07-12) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### WBS-7.14 KIS OpenAPI Rate Limit Throttling (SemaphoreSlim) 탑재
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | KIS API 호출 시 동시성 충돌 및 초당 횟수 초과 에러 방지를 위해 실전(150ms)/모의(400ms) 지연 락 추가 |
|
||||||
|
| **담당 파일** | `src/dotnet/QuantEngine.Infrastructure/Services/KisApiClient.cs` |
|
||||||
|
| **상태** | ✅ 완료 (2026-07-12) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### WBS-7.15 Gitea CI/CD 배포 워크플로 체인 직렬화
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 배포 선후 관계 꼬임 방지를 위해 CI (Validators) ➡ Prepare Release ➡ Deploy-Prod 순차적 실행 연결 |
|
||||||
|
| **담당 파일** | `.gitea/workflows/prepare-release.yml`, `.gitea/workflows/deploy-prod.yml` |
|
||||||
|
| **상태** | ✅ 완료 (2026-07-12) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### WBS-7.16 배포 버전 및 version.txt 동적 런타임 맵핑
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 빌드 시점에 version.txt를 함께 인쇄하고 C# 런타임이 이를 동적 조회하도록 교정하여 버저닝 오차 해결 |
|
||||||
|
| **담당 파일** | `src/dotnet/QuantEngine.Web/Pages/Account/Login.cshtml.cs`, `src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml.cs`, `.gitea/workflows/prepare-release.yml` |
|
||||||
|
| **상태** | ✅ 완료 (2026-07-12) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### WBS-8: 실증 전환 & 운영 정규화 (Phase 8, 2026-07~09)
|
### WBS-8: 실증 전환 & 운영 정규화 (Phase 8, 2026-07~09)
|
||||||
|
|
||||||
> WBS-7 구조적 경화 완료 후, 실거래 데이터 누적을 통한 이론적 임계값의 실증적 검증 및 운영 안정화.
|
> WBS-7 구조적 경화 완료 후, 실거래 데이터 누적을 통한 이론적 임계값의 실증적 검증 및 운영 안정화.
|
||||||
@@ -1248,6 +1298,17 @@ LLM이 런타임에 이런 stale spec을 사실로 읽으면 할루시네이션
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### WBS-8.11 과거 데이터 Replay 기반 캘리브레이션 트랙
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 실거래 T+20 결과 30건 적재 대기 시간 동안, 과거 1년치 역사적 데이터를 SQLite/Postgresql 로부터 가져와 시뮬레이션 기반으로 ALPHA_CALIBRATION_V2 보정 알고리즘을 1차 검증 및 검정하는 피드백 파이프라인 개발 |
|
||||||
|
| **담당 파일** | `tools/build_replay_calibration_v1.py` (신규), `spec/calibration_registry.yaml` |
|
||||||
|
| **성공 기준** | 모의 캘리브레이션 실행 후 최적 가중치 업데이트가 calibration_registry.yaml 에 갱신 적용되는지 테스트 |
|
||||||
|
| **상태** | ⏳ 대기 (구조 설계 중) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### WBS-9: 성능 최적화 & 엔터프라이즈 안정화 (Phase 9, 2026-08~10)
|
### WBS-9: 성능 최적화 & 엔터프라이즈 안정화 (Phase 9, 2026-08~10)
|
||||||
|
|
||||||
> WBS-8의 실증 검증 완료 후, 성능 최적화와 운영 안정성을 극대화하는 단계.
|
> WBS-8의 실증 검증 완료 후, 성능 최적화와 운영 안정성을 극대화하는 단계.
|
||||||
@@ -1403,8 +1464,21 @@ WBS-8.8 (KIS 리팩터) — 독립적 (원격 병행)
|
|||||||
|
|
||||||
> **📌 보강 문서(2026-06-30):** 본 WBS-10 의 다수 항목이 `완료` 표기되어 있으나 실측 결과 일부 괴리(10.6 파이프라인·10.9 보안 실질 미완성)가 확인되었다. 마이그레이션 완성 우선 + 상용화 잔여 작업의 재정의는 [WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md](./WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md) 참조.
|
> **📌 보강 문서(2026-06-30):** 본 WBS-10 의 다수 항목이 `완료` 표기되어 있으나 실측 결과 일부 괴리(10.6 파이프라인·10.9 보안 실질 미완성)가 확인되었다. 마이그레이션 완성 우선 + 상용화 잔여 작업의 재정의는 [WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md](./WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md) 참조.
|
||||||
|
|
||||||
|
> 상세 작업 가이드(YAML): [WBS_10_DOTNET_MIGRATION_ROADMAP.yaml](./WBS_10_DOTNET_MIGRATION_ROADMAP.yaml)
|
||||||
|
> 실행 경로 인벤토리: [WBS_10_DOTNET_MIGRATION_INVENTORY.yaml](./WBS_10_DOTNET_MIGRATION_INVENTORY.yaml)
|
||||||
|
> 실행 분해 계획: [WBS_10_DOTNET_MIGRATION_EXECUTION_PLAN.yaml](./WBS_10_DOTNET_MIGRATION_EXECUTION_PLAN.yaml)
|
||||||
|
> 실행 분해 검증기: `tools/validate_dotnet_migration_execution_plan_v1.py`
|
||||||
|
> parity 계약: [WBS_10_DOTNET_PARITY_CONTRACT.yaml](./WBS_10_DOTNET_PARITY_CONTRACT.yaml)
|
||||||
|
> provenance 계약: [WBS_10_DOTNET_PROVENANCE_CONTRACT.yaml](./WBS_10_DOTNET_PROVENANCE_CONTRACT.yaml)
|
||||||
|
> scheduler contract: [WBS_10_DOTNET_SCHEDULER_CONTRACT.yaml](./WBS_10_DOTNET_SCHEDULER_CONTRACT.yaml)
|
||||||
|
> normalization contract: [WBS_10_DOTNET_NORMALIZATION_CONTRACT.yaml](./WBS_10_DOTNET_NORMALIZATION_CONTRACT.yaml)
|
||||||
|
> idempotency contract: [WBS_10_DOTNET_IDEMPOTENCY_CONTRACT.yaml](./WBS_10_DOTNET_IDEMPOTENCY_CONTRACT.yaml)
|
||||||
|
> ci/cd chain contract: [WBS_10_DOTNET_CICD_CHAIN_CONTRACT.yaml](./WBS_10_DOTNET_CICD_CHAIN_CONTRACT.yaml)
|
||||||
|
> domain parity backlog: [WBS_10_DOTNET_DOMAIN_PARITY_BACKLOG.yaml](./WBS_10_DOTNET_DOMAIN_PARITY_BACKLOG.yaml)
|
||||||
|
> read model contract: [WBS_10_DOTNET_READ_MODEL_CONTRACT.yaml](./WBS_10_DOTNET_READ_MODEL_CONTRACT.yaml)
|
||||||
|
|
||||||
> 현황 진단(2026-06-26): .NET 프로젝트는 Python 엔진(41 모듈, 14,500 LOC) 대비 5~10%(~1,400 LOC) 수준.
|
> 현황 진단(2026-06-26): .NET 프로젝트는 Python 엔진(41 모듈, 14,500 LOC) 대비 5~10%(~1,400 LOC) 수준.
|
||||||
> Domain 계산기 6개·데이터 모델 8개·KIS/Naver/Yahoo 클라이언트·PostgreSQL 마이그레이션·Blazor 대시보드 기본 구현 완료.
|
> Domain 계산기 6개·데이터 모델 8개·KIS/Naver/Yahoo 클라이언트·PostgreSQL 마이그레이션·Razor Pages 어드민 대시보드 기본 구현 완료.
|
||||||
> **미구현**: Application 서비스 일부, 공식 엔진, 하네스 주입, 파이프라인 오케스트레이터.
|
> **미구현**: Application 서비스 일부, 공식 엔진, 하네스 주입, 파이프라인 오케스트레이터.
|
||||||
> **발견된 결함 5건**: D1) Tests.csproj Core ProjectReference 누락, D2) Tests sln 미등록, D3) appsettings.json 비밀번호 하드코딩, D4) NU1510 불필요 패키지, D5) Class1.cs placeholder 2개.
|
> **발견된 결함 5건**: D1) Tests.csproj Core ProjectReference 누락, D2) Tests sln 미등록, D3) appsettings.json 비밀번호 하드코딩, D4) NU1510 불필요 패키지, D5) Class1.cs placeholder 2개.
|
||||||
|
|
||||||
@@ -1420,7 +1494,7 @@ WBS-10.1 (기반 결함 수정)
|
|||||||
├──→ WBS-10.7 (Application 서비스)
|
├──→ WBS-10.7 (Application 서비스)
|
||||||
│ └──→ WBS-10.8 (데이터 수집 오케스트레이터)
|
│ └──→ WBS-10.8 (데이터 수집 오케스트레이터)
|
||||||
├──→ WBS-10.9 (보안 강화)
|
├──→ WBS-10.9 (보안 강화)
|
||||||
└──→ WBS-10.10 (Blazor 대시보드 고도화)
|
└──→ WBS-10.10 (Razor Pages 어드민 대시보드 고도화)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1659,11 +1733,11 @@ WBS-10.1 (기반 결함 수정)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### WBS-10.10 Blazor 대시보드 고도화
|
#### WBS-10.10 Razor Pages 어드민 대시보드 고도화
|
||||||
|
|
||||||
| 항목 | 내용 |
|
| 항목 | 내용 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| **작업** | Python snapshot_admin_server_v1.py의 편집/조회 기능을 Blazor SSR로 확장. 기본 템플릿 페이지 제거 |
|
| **작업** | Python snapshot_admin_server_v1.py의 편집/조회 기능을 Razor Pages 뷰 및 핸들러로 구현. 기본 템플릿 페이지 제거 |
|
||||||
| **현재 상태** | `Dashboard.razor`는 데이터 비의존형 상태표시로 단순화되었고, `Operations.razor`가 `Temp/operational_report.json` 고정 렌더 경로를 제공하며, Counter/Weather 기본 페이지는 삭제됨. 공개 배포본은 아직 이전 빌드가 남아 있을 수 있으므로 CI/CD 동기화가 필요함 |
|
| **현재 상태** | `Dashboard.razor`는 데이터 비의존형 상태표시로 단순화되었고, `Operations.razor`가 `Temp/operational_report.json` 고정 렌더 경로를 제공하며, Counter/Weather 기본 페이지는 삭제됨. 공개 배포본은 아직 이전 빌드가 남아 있을 수 있으므로 CI/CD 동기화가 필요함 |
|
||||||
| **담당 파일** | `src/dotnet/QuantEngine.Web/Components/Pages/Dashboard.razor`, `Operations.razor`, `NavMenu.razor` |
|
| **담당 파일** | `src/dotnet/QuantEngine.Web/Components/Pages/Dashboard.razor`, `Operations.razor`, `NavMenu.razor` |
|
||||||
| **상태** | 완료 |
|
| **상태** | 완료 |
|
||||||
@@ -1686,28 +1760,39 @@ WBS-10.1 (기반 결함 수정)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### WBS-10.11 Blazor 및 API-First 개발 가이드라인 수립
|
#### WBS-10.11 Razor Pages 개발 가이드라인 수립
|
||||||
| 항목 | 내용 |
|
| 항목 | 내용 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| **작업** | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md)의 API-First 아키텍처, 이중 토큰 인증, SignalR, MudBlazor UX 패턴 등 Blazor 관련 핵심 개발 지침을 [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md)에 차용/반영 |
|
| **작업** | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md)의 API-First 아키텍처, 이중 토큰 인증, SignalR, Tabler UX 및 CSRF 방어 등 Razor Pages 관련 핵심 개발 지침을 [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md)에 차용/반영 |
|
||||||
| **현재 상태** | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md) 분석 후 [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md)의 Section 5b로 이식 완료 |
|
| **현재 상태** | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md) 분석 후 [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md)의 Section 5b로 이식 완료 |
|
||||||
| **담당 파일** | [docs/ROADMAP_WBS.md](file:///C:/Temp/data_feed/docs/ROADMAP_WBS.md), [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md) |
|
| **담당 파일** | [docs/ROADMAP_WBS.md](file:///C:/Temp/data_feed/docs/ROADMAP_WBS.md), [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md) |
|
||||||
| **상태** | 완료 |
|
| **상태** | 완료 |
|
||||||
|
|
||||||
| 세부 WBS | 작업 | 성공 판단 데이터 |
|
| 세부 WBS | 작업 | 성공 판단 데이터 |
|
||||||
|----------|------|------------------|
|
|----------|------|------------------|
|
||||||
| 10.11.1 | CLAUDE.md의 Blazor 참조 지침 핵심사항 추출 및 공식화 | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md) 분석 내역 도출 |
|
| 10.11.1 | CLAUDE.md 및 실제 적용된 Razor Pages 지침 핵심사항 추출 및 공식화 | [Temp/CLAUDE.md](file:///C:/Temp/data_feed/Temp/CLAUDE.md) 분석 내역 도출 |
|
||||||
| 10.11.2 | AGENTS.md에 Blazor 개발 규칙 5b 섹션 신설 및 적용 | [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md) 내 5b 섹션 코드 삽입 완료 |
|
| 10.11.2 | AGENTS.md에 Razor Pages 개발 규칙 5b 섹션 신설 및 적용 | [AGENTS.md](file:///C:/Temp/data_feed/AGENTS.md) 내 5b 섹션 코드 삽입 완료 |
|
||||||
| 10.11.3 | 스펙 검증 스크립트 실행을 통한 구성 유효성 검증 | `validate_specs.py` 무오류 통과 |
|
| 10.11.3 | 스펙 검증 스크립트 실행을 통한 구성 유효성 검증 | `validate_specs.py` 무오류 통과 |
|
||||||
|
|
||||||
**성공 하네스 (데이터 기준)**:
|
**성공 하네스 (데이터 기준)**:
|
||||||
```
|
```
|
||||||
검증: python tools/validate_specs.py → EXIT 0
|
검증: python tools/validate_specs.py → EXIT 0
|
||||||
검증: C:\Temp\data_feed\AGENTS.md 내에 '5b. Blazor & API-First 개발 규칙' 및 'IXxxBrowserClient', 'TokenRefreshHandler' 키워드 존재
|
검증: C:\Temp\data_feed\AGENTS.md 내에 '5b. Razor Pages 개발 규칙' 및 'IXxxBrowserClient', 'TokenRefreshHandler' 키워드 존재
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### WBS-10.12 Playwright 기반 Razor Pages 어드민 UI E2E 자동화
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| **작업** | 대시보드 로그인, 데이터 수집 상세 조회, DB 테이블 변경 및 저장 폼 제출 등 핵심 UI 시나리오에 대해 Playwright를 이용한 무인 검증 스크립트 작성 및 CI 파이프라인 탑재 |
|
||||||
|
| **담당 파일** | `tests/e2e/RazorPagesSmokeTests.cs` (신규), `.gitea/workflows/ci.yml` |
|
||||||
|
| **성공 기준** | CI 파이프라인 실행 시 Playwright 테스트 스위트가 에러 없이 모두 PASS 완료 |
|
||||||
|
| **상태** | ⏳ 대기 (구조 설계 중) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 3. 완성도 로드맵 매트릭스
|
## 3. 완성도 로드맵 매트릭스
|
||||||
|
|
||||||
| WBS | 우선순위 | 난이도 | 선행조건 | 예상 기간 | 현재 완성도 |
|
| WBS | 우선순위 | 난이도 | 선행조건 | 예상 기간 | 현재 완성도 |
|
||||||
@@ -1755,8 +1840,8 @@ WBS-10.1 (기반 결함 수정)
|
|||||||
| 10.7 Application 서비스 | 🟠 High | 중간 | 10.1 | 3시간 | 0% |
|
| 10.7 Application 서비스 | 🟠 High | 중간 | 10.1 | 3시간 | 0% |
|
||||||
| 10.8 데이터 수집 오케스트레이터 | 🟡 Medium | 중간 | 10.7 | 4시간 | 0% |
|
| 10.8 데이터 수집 오케스트레이터 | 🟡 Medium | 중간 | 10.7 | 4시간 | 0% |
|
||||||
| 10.9 보안 강화 | 🟠 High | 낮음 | 10.1 | 1시간 | 0% |
|
| 10.9 보안 강화 | 🟠 High | 낮음 | 10.1 | 1시간 | 0% |
|
||||||
| 10.10 Blazor 대시보드 고도화 | 🟡 Medium | 중간 | 10.7 | 4시간 | 0% |
|
| 10.10 Razor Pages 어드민 대시보드 고도화 | 🟡 Medium | 중간 | 10.7 | 4시간 | 0% |
|
||||||
| 10.11 Blazor 개발 지침 차용 | 🟢 Low | 낮음 | 없음 | 1시간 | **100%** ✅ (2026-06-29) |
|
| 10.11 Razor Pages 개발 지침 수립 | 🟢 Low | 낮음 | 없음 | 1시간 | **100%** ✅ (2026-06-29) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -2271,3 +2356,30 @@ python tools/validate_snapshot_admin_web_v1.py
|
|||||||
> 이 문서는 `docs/ROADMAP_WBS.md` 에 저장됩니다.
|
> 이 문서는 `docs/ROADMAP_WBS.md` 에 저장됩니다.
|
||||||
> 스프린트 완료마다 **완성도 KPI 섹션**을 업데이트하세요.
|
> 스프린트 완료마다 **완성도 KPI 섹션**을 업데이트하세요.
|
||||||
> 모든 WBS 항목의 구현 시 반드시 **하네스 성공 기준**을 먼저 충족 후 다음 단계로 진행합니다.
|
> 모든 WBS 항목의 구현 시 반드시 **하네스 성공 기준**을 먼저 충족 후 다음 단계로 진행합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 차세대 퀀트 엔진 로드맵/WBS 포인터 (2026-07-12)
|
||||||
|
|
||||||
|
이후의 퀀트 엔진 진화 로드맵(M0–M5: 실증 하네스 → 수집 배선 → 시계열 저장소 →
|
||||||
|
실데이터 팩터 → 백테스팅 → 포트폴리오/레짐)과 상세 WBS는 **기계 판정 YAML**로 관리한다:
|
||||||
|
|
||||||
|
- **스펙(단일 진실 원천)**: `spec/60_quant_engine_wbs.yaml` (formula_id: `QUANT_ENGINE_WBS_V1`)
|
||||||
|
- **단일 작업 검증**: `python tools/verify_wbs_task_v1.py --task <TASK_ID>` → `Temp/evidence/<TASK_ID>/verdict.json`
|
||||||
|
- **전체 WBS 게이트**: `python tools/validate_quant_engine_wbs_v1.py` → `Temp/quant_engine_wbs_v1.json`
|
||||||
|
|
||||||
|
완료 판정 원칙: 작업은 게이트 실행(PASS)으로만 `DONE` 이 될 수 있다.
|
||||||
|
BE = PostgreSQL 쿼리 + Serilog 로그 패턴 + JSON 아티팩트, FE = Playwright(DOM assert + API 기대값 대조 + 스크린샷).
|
||||||
|
|
||||||
|
### 폐기: schemas/generated/ + src/quant_engine/models/generated/ (2026-07-12, QE-M0-07)
|
||||||
|
|
||||||
|
`schemas/generated/*.schema.json`(174) + `src/quant_engine/models/generated/*.py`(347)로
|
||||||
|
구성된 스키마-모델 생성 레이어를 **폐기**했다. 기존 `runtime/python/core/formulas/generated/`
|
||||||
|
(172개 stub)와 동일한 목적(공식 메타데이터 서술)을 범용 wrapper로 중복 구현했을 뿐 실질
|
||||||
|
계산 로직이 전혀 없었고, 검증도 `validate_schema_model_generation_v1.py`가 파일 개수만
|
||||||
|
세는 가짜 게이트였다(QUANT_ENGINE_WBS_V1 재검토에서 발견). CI 시간만 늘리고 기능적
|
||||||
|
이득이 없어 삭제. `tools/generate_schema_model_generation_evidence_v1.py`,
|
||||||
|
`tools/validate_schema_model_generation_v1.py`, `src/quant_engine/generate_models_from_schema.py`
|
||||||
|
및 ci.yml/`spec/41_release_dag.yaml`의 관련 스텝·노드도 함께 제거했다.
|
||||||
|
`schemas/generated/gas_adapter_contract.schema.json`은 별개 목적(GAS 어댑터 계약 검증,
|
||||||
|
`validate_gas_adapter_contract_v1.py`)으로 쓰이므로 보존.
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_CICD_CHAIN_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "CI, prepare-release, deploy-prod 순차 게이트를 고정한다."
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
ci:
|
||||||
|
file: .gitea/workflows/ci.yml
|
||||||
|
name: "Validators (Pushes and Pull Requests)"
|
||||||
|
triggers:
|
||||||
|
- push: main
|
||||||
|
- pull_request: main
|
||||||
|
role: "upstream validator"
|
||||||
|
prepare_release:
|
||||||
|
file: .gitea/workflows/prepare-release.yml
|
||||||
|
name: "Prepare Release"
|
||||||
|
triggers:
|
||||||
|
- workflow_run: Validators (Pushes and Pull Requests)
|
||||||
|
- workflow_dispatch
|
||||||
|
role: "release builder"
|
||||||
|
upstream_gate: "Validators (Pushes and Pull Requests) success"
|
||||||
|
deploy_prod:
|
||||||
|
file: .gitea/workflows/deploy-prod.yml
|
||||||
|
name: "Deploy to Production"
|
||||||
|
triggers:
|
||||||
|
- workflow_run: Prepare Release
|
||||||
|
- workflow_dispatch
|
||||||
|
role: "production deployer"
|
||||||
|
upstream_gate: "Prepare Release success"
|
||||||
|
|
||||||
|
dependency_chain:
|
||||||
|
- "Validators (Pushes and Pull Requests) -> Prepare Release -> Deploy to Production"
|
||||||
|
|
||||||
|
required_guards:
|
||||||
|
- "prepare-release는 Validators 성공 없이는 실행 금지"
|
||||||
|
- "deploy-prod는 Prepare Release 성공 없이는 실행 금지"
|
||||||
|
- "deploy-prod는 upstream CI SHA를 release tag와 대조"
|
||||||
|
- "모든 단계는 concurrency group을 사용해 동일 SHA 중복 실행을 차단"
|
||||||
|
|
||||||
|
health_checks:
|
||||||
|
- "upstream workflow conclusion == success"
|
||||||
|
- "release tag sha matches workflow_run head_sha"
|
||||||
|
- "artifact 존재 확인"
|
||||||
|
- "SSH/Gitea secret 존재 확인"
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "순차 게이트는 workflow_run 연결과 검증 스텝 둘 다 필요하다."
|
||||||
|
- "병렬 실행은 금지된다."
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_DOMAIN_PARITY_BACKLOG_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "핵심 계산기 parity 대상과 우선순위를 고정한다."
|
||||||
|
|
||||||
|
coverage_min: 1.0
|
||||||
|
tolerance_policy:
|
||||||
|
numeric_default: 0
|
||||||
|
text_default: exact
|
||||||
|
factor_calculator_numeric: 0.000001
|
||||||
|
exit_stop_price_numeric: 0.0001
|
||||||
|
|
||||||
|
parity_targets:
|
||||||
|
- target_id: formula_engine_timing
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
priority: 1
|
||||||
|
reason: "timing decision은 downstream routing의 선행 게이트"
|
||||||
|
- target_id: formula_engine_sell
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
priority: 2
|
||||||
|
reason: "sell ratio/action은 실행 표 생성의 핵심"
|
||||||
|
- target_id: formula_engine_final
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
priority: 3
|
||||||
|
reason: "final decision은 보고/배포의 최종 산출"
|
||||||
|
- target_id: exit_stop_price
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/ExitDecisions.cs
|
||||||
|
priority: 4
|
||||||
|
reason: "손절가 절대값 일치가 필요"
|
||||||
|
- target_id: exit_stop_ladder
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/ExitDecisions.cs
|
||||||
|
priority: 5
|
||||||
|
reason: "워터폴 선형 처리 검증"
|
||||||
|
- target_id: exit_heat_thresholds
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/ExitDecisions.cs
|
||||||
|
priority: 6
|
||||||
|
reason: "동적 열감 임계값 일치"
|
||||||
|
- target_id: factor_calculator
|
||||||
|
source: src/dotnet/QuantEngine.Core/Domain/FactorCalculator.cs
|
||||||
|
priority: 7
|
||||||
|
reason: "정규화된 입력 순서에서 deterministic output 보장"
|
||||||
|
|
||||||
|
coverage_rule:
|
||||||
|
- "priority 1..7 모두 존재해야 한다"
|
||||||
|
- "tolerance_policy는 숫자/텍스트 기본값을 정의해야 한다"
|
||||||
|
- "새 parity target은 reference fixture와 함께만 추가한다"
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "parity는 기능 추가가 아니라 회귀 차단 장치다."
|
||||||
|
- "수치 재계산은 reference fixture 외에서 하지 않는다."
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_IDEMPOTENCY_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "중복 실행 방지, lock/lease 정책, 재시도 경계를 표준화한다."
|
||||||
|
|
||||||
|
lock_domain:
|
||||||
|
canonical_table: quantengine.workspace_lock
|
||||||
|
fields:
|
||||||
|
- domain
|
||||||
|
- target_ref
|
||||||
|
- locked_by
|
||||||
|
- reason
|
||||||
|
- locked_at
|
||||||
|
invariant:
|
||||||
|
- "같은 domain + target_ref 조합은 동시에 하나만 존재"
|
||||||
|
- "잠금 해제는 동일 domain + target_ref 로만 수행"
|
||||||
|
- "잠금 없는 실행은 retryable 작업으로 취급하지 않는다"
|
||||||
|
|
||||||
|
idempotency_key:
|
||||||
|
required: true
|
||||||
|
pattern: "{job_id}:{resource_key}:{run_scope}"
|
||||||
|
scope_examples:
|
||||||
|
- "daily-collection:collection:yyyyMMdd"
|
||||||
|
- "hourly-price-update:ticker:yyyyMMddHH"
|
||||||
|
- "weekly-report:report:yyyy-'W'ww"
|
||||||
|
- "monthly-optimization:optimization:yyyy-MM"
|
||||||
|
|
||||||
|
lease_policy:
|
||||||
|
required: true
|
||||||
|
fields:
|
||||||
|
- lease_owner
|
||||||
|
- timeout_policy
|
||||||
|
- retry_policy
|
||||||
|
retry_policy:
|
||||||
|
max_attempts: 3
|
||||||
|
backoff: exponential
|
||||||
|
retryable_errors:
|
||||||
|
- transient network failure
|
||||||
|
- upstream timeout
|
||||||
|
- deadlock detected
|
||||||
|
non_retryable_errors:
|
||||||
|
- validation failure
|
||||||
|
- contract failure
|
||||||
|
- missing configuration
|
||||||
|
|
||||||
|
duplicate_execution_guards:
|
||||||
|
- "동일 job_id/resource_key/run_scope 중복 호출 금지"
|
||||||
|
- "동일 lock_domain이 점유 중이면 새 실행은 blocked"
|
||||||
|
- "중복 실행이 발생하면 audit는 남기되 write path는 재진입 금지"
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "idempotency는 hash 추정이 아니라 명시된 key 조합만 사용한다."
|
||||||
|
- "lock은 수동 승인 워크플로와 동일한 canonical table을 사용한다."
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_MIGRATION_EXECUTION_PLAN_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
source_of_truth:
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_ROADMAP.yaml
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_INVENTORY.yaml
|
||||||
|
|
||||||
|
goal: ".NET 엔진 고도화를 실제 작업 순서로 착수 가능한 수준까지 분해한다."
|
||||||
|
|
||||||
|
work_packages:
|
||||||
|
- wp_id: WBS-10-WP1
|
||||||
|
title: "운영 경로 분해 및 전환 경계 확정"
|
||||||
|
objective: "Python harness / .NET domain / .NET application / .NET web / read model 경계를 고정한다."
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-A1
|
||||||
|
inputs:
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_INVENTORY.yaml
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_ROADMAP.yaml
|
||||||
|
outputs:
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_INVENTORY.yaml
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_EXECUTION_PLAN.yaml
|
||||||
|
success_data:
|
||||||
|
schema: yaml
|
||||||
|
fields:
|
||||||
|
- route_id
|
||||||
|
- classification
|
||||||
|
- keep_or_migrate
|
||||||
|
- owner_file
|
||||||
|
- note
|
||||||
|
pass_condition: "migrate 대상과 keep 대상이 혼동 없이 분리됨"
|
||||||
|
|
||||||
|
- wp_id: WBS-10-WP2
|
||||||
|
title: "Domain parity 우선순위 확정"
|
||||||
|
objective: "핵심 계산기와 하네스 parity 대상을 먼저 고정한다."
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-WP1
|
||||||
|
inputs:
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FactorCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FormulaEngineTests.cs
|
||||||
|
outputs:
|
||||||
|
- Temp/wbs10_domain_parity_backlog.json
|
||||||
|
success_data:
|
||||||
|
schema: json
|
||||||
|
fields:
|
||||||
|
- formula_id
|
||||||
|
- parity_targets
|
||||||
|
- tolerance
|
||||||
|
- coverage_min
|
||||||
|
pass_condition: "핵심 계산기 parity 대상이 누락 없이 나열됨"
|
||||||
|
|
||||||
|
- wp_id: WBS-10-WP3
|
||||||
|
title: "스케줄러 서비스 수준 강화 착수"
|
||||||
|
objective: "SchedulerService를 상태/의존성/재시도/감사 추적 서비스로 진화시킨다."
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-WP1
|
||||||
|
inputs:
|
||||||
|
- src/dotnet/QuantEngine.Web/Services/SchedulerService.cs
|
||||||
|
- spec/41_release_dag.yaml
|
||||||
|
outputs:
|
||||||
|
- Temp/wbs10_scheduler_service_backlog.yaml
|
||||||
|
success_data:
|
||||||
|
schema: yaml
|
||||||
|
fields:
|
||||||
|
- state_machine
|
||||||
|
- dependency_edges
|
||||||
|
- retry_policy
|
||||||
|
- audit_fields
|
||||||
|
pass_condition: "현재 cron형 호출과 서비스 수준 제어면의 차이가 정의됨"
|
||||||
|
|
||||||
|
- wp_id: WBS-10-WP4
|
||||||
|
title: "read model 분리 착수"
|
||||||
|
objective: "운영 조회를 원장/집계와 분리한다."
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-WP1
|
||||||
|
inputs:
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml.cs
|
||||||
|
outputs:
|
||||||
|
- Temp/wbs10_read_model_boundary.yaml
|
||||||
|
success_data:
|
||||||
|
schema: yaml
|
||||||
|
fields:
|
||||||
|
- projection
|
||||||
|
- source_of_truth
|
||||||
|
- refresh_mode
|
||||||
|
- staleness_budget
|
||||||
|
pass_condition: "조회 모델과 원장 모델의 경계가 설명됨"
|
||||||
|
|
||||||
|
execution_order:
|
||||||
|
- WBS-10-WP1
|
||||||
|
- WBS-10-WP2
|
||||||
|
- WBS-10-WP3
|
||||||
|
- WBS-10-WP4
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "이 문서는 실행 가능한 작업 분해용이며, 권위는 roadmap/inventory에 남긴다."
|
||||||
|
- "모든 success_data는 하네스가 아닌 착수 기준으로 사용한다."
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_MIGRATION_INVENTORY_V1
|
||||||
|
status: draft
|
||||||
|
owner: QuantEngine
|
||||||
|
scope:
|
||||||
|
goal: ".NET 고도화 전환 우선순위를 결정하기 위한 운영 경로 인벤토리"
|
||||||
|
classification:
|
||||||
|
- python_harness
|
||||||
|
- dotnet_domain
|
||||||
|
- dotnet_application
|
||||||
|
- dotnet_web
|
||||||
|
- read_model
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- route_id: python_harness_validation
|
||||||
|
path:
|
||||||
|
- tools/validate_quant_engine_wbs_v1.py
|
||||||
|
- tools/validate_dotnet_migration_roadmap_v1.py
|
||||||
|
- tests/unit/test_validate_dotnet_migration_roadmap_v1.py
|
||||||
|
classification: python_harness
|
||||||
|
keep_or_migrate: keep
|
||||||
|
reason: "검증 도구는 운영 엔진이 아니라 하네스/계약 검사 계층이다."
|
||||||
|
|
||||||
|
- route_id: python_wbs_source
|
||||||
|
path:
|
||||||
|
- spec/60_quant_engine_wbs.yaml
|
||||||
|
- docs/WBS_10_DOTNET_MIGRATION_ROADMAP.yaml
|
||||||
|
classification: python_harness
|
||||||
|
keep_or_migrate: keep
|
||||||
|
reason: "권위 문서와 상세 로드맵은 운영 실행물이 아니라 계약 문서다."
|
||||||
|
|
||||||
|
- route_id: dotnet_core_formula_engine
|
||||||
|
path:
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FactorCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/AntiChasingCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/ProfitLockCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/PullbackTriggerCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/SellPriceSanityChecker.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/KrxTickNormalizer.cs
|
||||||
|
classification: dotnet_domain
|
||||||
|
keep_or_migrate: migrate
|
||||||
|
reason: "운영 계산의 canonical engine 후보이며 parity harness의 주 대상이다."
|
||||||
|
|
||||||
|
- route_id: dotnet_application_orchestration
|
||||||
|
path:
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/PipelineOrchestrator.cs
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/KisDataCollectionOrchestrator.cs
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/HistoryIngestionService.cs
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/PriceDataNormalizer.cs
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/SourcePriorityResolver.cs
|
||||||
|
- src/dotnet/QuantEngine.Application/Services/DataCollectionService.cs
|
||||||
|
classification: dotnet_application
|
||||||
|
keep_or_migrate: migrate
|
||||||
|
reason: "Python 오케스트레이션/수집/정규화 흐름을 .NET 서비스 계층으로 수렴시킨다."
|
||||||
|
|
||||||
|
- route_id: dotnet_web_scheduler
|
||||||
|
path:
|
||||||
|
- src/dotnet/QuantEngine.Web/Services/SchedulerService.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Operations/Index.cshtml.cs
|
||||||
|
classification: dotnet_web
|
||||||
|
keep_or_migrate: migrate
|
||||||
|
reason: "스케줄러와 운영 제어면은 서비스 수준으로 고도화 대상이다."
|
||||||
|
|
||||||
|
- route_id: dotnet_read_models
|
||||||
|
path:
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Monitoring/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Database/Index.cshtml.cs
|
||||||
|
classification: read_model
|
||||||
|
keep_or_migrate: migrate
|
||||||
|
reason: "운영 조회는 역정규화 read model로 분리한다."
|
||||||
|
|
||||||
|
priority_order:
|
||||||
|
- python_harness_validation
|
||||||
|
- python_wbs_source
|
||||||
|
- dotnet_core_formula_engine
|
||||||
|
- dotnet_application_orchestration
|
||||||
|
- dotnet_web_scheduler
|
||||||
|
- dotnet_read_models
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "운영 경로는 keep_or_migrate가 migrate인 대상만 .NET canonical 대상으로 본다."
|
||||||
|
- "python_harness는 thin wrapper 또는 검증용으로만 유지한다."
|
||||||
|
- "read_model은 원장 대체가 아니라 서빙 전용이다."
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_MIGRATION_ROADMAP_V1
|
||||||
|
title: "WBS-10 .NET 엔진 고도화 상세 로드맵"
|
||||||
|
owner: "QuantEngine"
|
||||||
|
source_of_truth:
|
||||||
|
- docs/ROADMAP_WBS.md
|
||||||
|
- spec/60_quant_engine_wbs.yaml
|
||||||
|
- spec/41_release_dag.yaml
|
||||||
|
- spec/00_execution_contract.yaml
|
||||||
|
|
||||||
|
scope:
|
||||||
|
goal: "Python 검증/보조 도구는 유지하고, 운영 엔진은 .NET으로 수렴시키며, 테이블 구조와 스케줄러를 서비스 수준으로 고도화한다."
|
||||||
|
non_goals:
|
||||||
|
- "가격/수량/임계값의 LLM 즉석 계산"
|
||||||
|
- "운영 경로의 Python 재도입"
|
||||||
|
- "원천 데이터의 무분별한 중복 저장"
|
||||||
|
|
||||||
|
principles:
|
||||||
|
- "Python은 harness, verification, conversion tooling에 집중한다."
|
||||||
|
- ".NET은 runtime engine, scheduler, API, operational read model을 담당한다."
|
||||||
|
- "쓰기 경로는 정규화, 읽기 경로는 의도된 역정규화로 분리한다."
|
||||||
|
- "모든 숫자는 provenance와 검증 아티팩트를 가져야 한다."
|
||||||
|
- "스케줄러는 단순 cron이 아니라 상태/의존성/재시도/감사 추적을 갖는 서비스로 취급한다."
|
||||||
|
|
||||||
|
roadmap:
|
||||||
|
phase_name: "WBS-10 .NET 엔진 고도화"
|
||||||
|
phase_goal: "Python-to-.NET 전환, 테이블 정규화/역정규화, 서비스급 스케줄러, parity harness 정착"
|
||||||
|
exit_gate: "dotnet runtime parity PASS + scheduler observability PASS + normalized/denormalized schema contract PASS + evidence artifacts recorded"
|
||||||
|
execution_order:
|
||||||
|
- WBS-10-A1
|
||||||
|
- WBS-10-B1
|
||||||
|
- WBS-10-C1
|
||||||
|
- WBS-10-A2
|
||||||
|
- WBS-10-B2
|
||||||
|
- WBS-10-C2
|
||||||
|
- WBS-10-A3
|
||||||
|
- WBS-10-B3
|
||||||
|
- WBS-10-C3
|
||||||
|
tracks:
|
||||||
|
- track_id: WBS-10-A
|
||||||
|
name: "Python → .NET 전환"
|
||||||
|
description: "운영 경로에서 Python 의존을 제거하고, 동일 결과를 내는 .NET canonical 구현으로 이식한다."
|
||||||
|
tasks:
|
||||||
|
- task_id: WBS-10-A1
|
||||||
|
title: "실행 경로 인벤토리 및 전환 우선순위 확정"
|
||||||
|
status: PENDING
|
||||||
|
depends_on: []
|
||||||
|
owner_files:
|
||||||
|
- src/quant_engine/
|
||||||
|
- tools/
|
||||||
|
- spec/60_quant_engine_wbs.yaml
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "운영 진입점 목록"
|
||||||
|
- "Python CLI/모듈 호출 지점"
|
||||||
|
- "배포/스케줄러 호출 경로"
|
||||||
|
expected_outputs:
|
||||||
|
- "전환 우선순위 표"
|
||||||
|
- "운영 경로 / 보조 경로 분리 결과"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: markdown
|
||||||
|
fields:
|
||||||
|
- route
|
||||||
|
- owner
|
||||||
|
- runtime
|
||||||
|
- keep_or_migrate
|
||||||
|
- notes
|
||||||
|
failure_conditions:
|
||||||
|
- "운영 경로와 보조 경로가 섞여 있으면 FAIL"
|
||||||
|
- "Python 운영 경로가 누락 없이 남아 있지 않으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-A1/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "운영 경로와 보조 경로가 문서화됨"
|
||||||
|
- "전환 대상/비대상 경로가 분리됨"
|
||||||
|
|
||||||
|
- task_id: WBS-10-A2
|
||||||
|
title: ".NET 도메인 서비스로 Python 계산 로직 이식"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-A1
|
||||||
|
owner_files:
|
||||||
|
- src/dotnet/QuantEngine.Core/
|
||||||
|
- src/dotnet/QuantEngine.Application/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "Python reference result"
|
||||||
|
- "현재 .NET implementation"
|
||||||
|
- "golden parity dataset"
|
||||||
|
expected_outputs:
|
||||||
|
- "동일 입력에 대한 .NET 결과"
|
||||||
|
- "Python 대비 parity diff 0 또는 허용오차 내"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: json
|
||||||
|
fields:
|
||||||
|
- formula_id
|
||||||
|
- input_digest
|
||||||
|
- python_output
|
||||||
|
- dotnet_output
|
||||||
|
- diff
|
||||||
|
- tolerance
|
||||||
|
- gate
|
||||||
|
failure_conditions:
|
||||||
|
- "diff가 tolerance를 초과하면 FAIL"
|
||||||
|
- "입력 digest가 없으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "dotnet test src/dotnet/QuantEngine.Core.Tests/QuantEngine.Core.Tests.csproj -c Release"
|
||||||
|
- "python tools/verify_wbs_task_v1.py --task WBS-10-A2"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-A2/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "Python reference와 .NET output이 parity를 만족"
|
||||||
|
- "핵심 계산이 서비스 계층으로 이동됨"
|
||||||
|
|
||||||
|
- task_id: WBS-10-A3
|
||||||
|
title: "Python thin-wrapper 정리 및 운영 금지 경로 분리"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-A2
|
||||||
|
owner_files:
|
||||||
|
- tools/
|
||||||
|
- src/quant_engine/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "현재 Python script 목록"
|
||||||
|
- "runtime entrypoint 목록"
|
||||||
|
expected_outputs:
|
||||||
|
- "운영용 thin wrapper만 남김"
|
||||||
|
- "직접 운영 경로 금지 목록"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- wrapper_path
|
||||||
|
- purpose
|
||||||
|
- runtime_usage
|
||||||
|
- allowed_or_disallowed
|
||||||
|
failure_conditions:
|
||||||
|
- "운영용으로 직접 호출 가능한 Python entrypoint가 남아 있으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-A3/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "운영 진입점이 .NET 또는 thin wrapper로만 남음"
|
||||||
|
|
||||||
|
- track_id: WBS-10-B
|
||||||
|
name: "테이블 정규화 + 역정규화"
|
||||||
|
description: "원천/원장/배포 이력을 정규화하고, UI/대시보드용 읽기 모델은 역정규화한다."
|
||||||
|
tasks:
|
||||||
|
- task_id: WBS-10-B1
|
||||||
|
title: "정규화 기준 테이블 계약 확정"
|
||||||
|
status: PENDING
|
||||||
|
depends_on: []
|
||||||
|
owner_files:
|
||||||
|
- spec/
|
||||||
|
- src/dotnet/QuantEngine.Infrastructure/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "source table 목록"
|
||||||
|
- "primary key / foreign key 정의"
|
||||||
|
- "중복 제거 대상"
|
||||||
|
expected_outputs:
|
||||||
|
- "canonical normalized schema"
|
||||||
|
- "table ownership map"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- table
|
||||||
|
- keys
|
||||||
|
- cardinality
|
||||||
|
- owner
|
||||||
|
- write_path
|
||||||
|
failure_conditions:
|
||||||
|
- "canonical table이 둘 이상이면 FAIL"
|
||||||
|
- "정규화 대상과 읽기 모델이 혼동되면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-B1/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "쓰기 경로의 canonical table contract가 문서화됨"
|
||||||
|
|
||||||
|
- task_id: WBS-10-B2
|
||||||
|
title: "운영 조회용 역정규화 read model 설계"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-B1
|
||||||
|
owner_files:
|
||||||
|
- src/dotnet/QuantEngine.Web/
|
||||||
|
- src/dotnet/QuantEngine.Application/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "대시보드/운영 화면 요구사항"
|
||||||
|
- "조회 성능 목표"
|
||||||
|
expected_outputs:
|
||||||
|
- "읽기 전용 denormalized projection"
|
||||||
|
- "refresh/update strategy"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- projection_name
|
||||||
|
- source_tables
|
||||||
|
- refresh_mode
|
||||||
|
- staleness_budget
|
||||||
|
- consumers
|
||||||
|
failure_conditions:
|
||||||
|
- "읽기 모델이 원천 원장과 직접 동일하면 FAIL"
|
||||||
|
- "staleness_budget 미정이면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-B2/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "읽기 모델이 원천 원장과 분리됨"
|
||||||
|
- "운영 화면이 read model만 참조함"
|
||||||
|
|
||||||
|
- task_id: WBS-10-B3
|
||||||
|
title: "중복/파생 데이터 경계 및 기술부채 방지 계약"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-B1
|
||||||
|
- WBS-10-B2
|
||||||
|
owner_files:
|
||||||
|
- spec/
|
||||||
|
- governance/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "allowed denormalization cases"
|
||||||
|
- "forbidden duplication cases"
|
||||||
|
expected_outputs:
|
||||||
|
- "파생 데이터 허용 규칙"
|
||||||
|
- "canonical source 정의"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- source_of_truth
|
||||||
|
- derived_table
|
||||||
|
- allowed_reason
|
||||||
|
- forbidden_reason
|
||||||
|
failure_conditions:
|
||||||
|
- "source_of_truth가 명시되지 않으면 FAIL"
|
||||||
|
- "금지 사유가 없는 중복이면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-B3/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "역정규화가 의도된 캐시/서빙으로만 허용됨"
|
||||||
|
|
||||||
|
- track_id: WBS-10-C
|
||||||
|
name: "서비스 수준 스케줄러"
|
||||||
|
description: "cron 수준을 넘어 상태 머신, idempotency, dependency, audit, retry를 갖는 스케줄러로 강화한다."
|
||||||
|
tasks:
|
||||||
|
- task_id: WBS-10-C1
|
||||||
|
title: "스케줄러 상태 머신 및 실행 이력 계약"
|
||||||
|
status: PENDING
|
||||||
|
depends_on: []
|
||||||
|
owner_files:
|
||||||
|
- src/dotnet/QuantEngine.Application/
|
||||||
|
- src/dotnet/QuantEngine.Web/Services/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "job state list"
|
||||||
|
- "transition rule"
|
||||||
|
- "run id / lease key"
|
||||||
|
expected_outputs:
|
||||||
|
- "pending/running/succeeded/failed/retrying/blocked 상태 정의"
|
||||||
|
- "audit trail schema"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- state
|
||||||
|
- allowed_transitions
|
||||||
|
- lease_owner
|
||||||
|
- timeout_policy
|
||||||
|
- audit_fields
|
||||||
|
failure_conditions:
|
||||||
|
- "상태 전이표가 없으면 FAIL"
|
||||||
|
- "lease_owner 또는 timeout_policy가 없으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-C1/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "스케줄러의 상태 전이가 데이터로 설명됨"
|
||||||
|
|
||||||
|
- task_id: WBS-10-C2
|
||||||
|
title: "idempotency 및 concurrency control"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-C1
|
||||||
|
owner_files:
|
||||||
|
- src/dotnet/QuantEngine.Application/
|
||||||
|
- spec/41_release_dag.yaml
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "중복 실행 시나리오"
|
||||||
|
- "동시 실행 금지 자원 목록"
|
||||||
|
expected_outputs:
|
||||||
|
- "중복 적재 방지"
|
||||||
|
- "자원별 lock/lease 정책"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- resource
|
||||||
|
- lock_key
|
||||||
|
- idempotency_key
|
||||||
|
- retry_policy
|
||||||
|
failure_conditions:
|
||||||
|
- "idempotency_key가 없으면 FAIL"
|
||||||
|
- "동시 실행 금지 자원 목록이 비어 있으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-C2/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "같은 run이 두 번 실행돼도 결과가 중복되지 않음"
|
||||||
|
|
||||||
|
- task_id: WBS-10-C3
|
||||||
|
title: "health gate + retry policy + dependency graph"
|
||||||
|
status: PENDING
|
||||||
|
depends_on:
|
||||||
|
- WBS-10-C1
|
||||||
|
- WBS-10-C2
|
||||||
|
owner_files:
|
||||||
|
- .gitea/workflows/
|
||||||
|
- src/dotnet/QuantEngine.Web/
|
||||||
|
success_data_guide:
|
||||||
|
required_inputs:
|
||||||
|
- "업스트림 의존성 목록"
|
||||||
|
- "retry 가능한 failure 유형"
|
||||||
|
- "health check 대상"
|
||||||
|
expected_outputs:
|
||||||
|
- "ci -> prepare-release -> deploy-prod 순차 게이트"
|
||||||
|
- "transient failure만 재시도"
|
||||||
|
expected_artifact_schema:
|
||||||
|
format: yaml
|
||||||
|
fields:
|
||||||
|
- upstream_workflow
|
||||||
|
- downstream_workflow
|
||||||
|
- retryable_errors
|
||||||
|
- health_checks
|
||||||
|
failure_conditions:
|
||||||
|
- "순차 게이트가 아닌 병렬 실행이면 FAIL"
|
||||||
|
- "retryable_errors가 비어 있으면 FAIL"
|
||||||
|
verification_commands:
|
||||||
|
- "python tools/validate_quant_engine_wbs_v1.py"
|
||||||
|
evidence_artifacts:
|
||||||
|
- "Temp/evidence/WBS-10-C3/verdict.json"
|
||||||
|
done_when:
|
||||||
|
- "스케줄러가 선행 성공 없이는 후속 실행을 시작하지 않음"
|
||||||
|
|
||||||
|
deliverables:
|
||||||
|
- "docs/WBS_10_DOTNET_MIGRATION_ROADMAP.yaml"
|
||||||
|
- "AGENTS.md routing update"
|
||||||
|
- "필요 시 docs/ROADMAP_WBS.md에 pointer 추가"
|
||||||
|
|
||||||
|
alignment:
|
||||||
|
canonical_status: "supplementary"
|
||||||
|
canonical_note: "이 YAML은 기존 WBS-10의 상세 실행 가이드이며, 권위는 docs/ROADMAP_WBS.md와 spec/60_quant_engine_wbs.yaml에 남긴다."
|
||||||
|
spec_task_map:
|
||||||
|
WBS-10.1: WBS-10-A1
|
||||||
|
WBS-10.2: WBS-10-C1
|
||||||
|
WBS-10.3: WBS-10-A2
|
||||||
|
WBS-10.4: WBS-10-A2
|
||||||
|
WBS-10.5: WBS-10-A2
|
||||||
|
WBS-10.6: WBS-10-C2
|
||||||
|
WBS-10.7: WBS-10-B2
|
||||||
|
WBS-10.8: WBS-10-C3
|
||||||
|
WBS-10.9: WBS-10-B3
|
||||||
|
WBS-10.10: WBS-10-B2
|
||||||
|
WBS-10.11: WBS-10-A3
|
||||||
|
WBS-10.12: WBS-10-C3
|
||||||
|
roadmap_section_map:
|
||||||
|
WBS-10.1: "기반 결함 수정"
|
||||||
|
WBS-10.2: "테스트 인프라 구축"
|
||||||
|
WBS-10.3: "Domain 계산기 Parity 검증 (Python ↔ C# 동등성)"
|
||||||
|
WBS-10.4: "공식 계산 엔진 C# 포팅 (compute_formula_outputs.py 대응)"
|
||||||
|
WBS-10.5: "하네스 주입 엔진 C# 포팅 (inject_computed_harness.py 대응)"
|
||||||
|
WBS-10.6: "파이프라인 오케스트레이터"
|
||||||
|
WBS-10.7: "Application 서비스 레이어 구축"
|
||||||
|
WBS-10.8: "데이터 수집 오케스트레이터"
|
||||||
|
WBS-10.9: "보안 강화"
|
||||||
|
WBS-10.10: "Razor Pages 어드민 대시보드 고도화"
|
||||||
|
WBS-10.11: "Razor Pages 개발 가이드라인 수립"
|
||||||
|
WBS-10.12: "Playwright 기반 Razor Pages 어드민 UI E2E 자동화"
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_NORMALIZATION_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "쓰기 경로 정규화와 읽기 경로 역정규화 경계를 고정한다."
|
||||||
|
|
||||||
|
canonical_write_path:
|
||||||
|
schema: engine_history
|
||||||
|
tables:
|
||||||
|
- source_observation
|
||||||
|
- factor_definition
|
||||||
|
- factor_observation
|
||||||
|
- decision_event
|
||||||
|
- decision_factor_evidence
|
||||||
|
- outcome_evaluation
|
||||||
|
invariant:
|
||||||
|
- "source_observation은 원천 관측 1건당 1행"
|
||||||
|
- "factor_definition은 (factor_id, factor_version) 단일 원장"
|
||||||
|
- "factor_observation은 observation_id를 반드시 참조"
|
||||||
|
- "decision_event는 decision_key로 단일 식별"
|
||||||
|
- "outcome_evaluation은 decision_id + horizon_days 조합으로 단일 식별"
|
||||||
|
|
||||||
|
canonical_read_path:
|
||||||
|
view: engine_history.training_example_v1
|
||||||
|
purpose: "모델 학습/캘리브레이션용 역정규화 projection"
|
||||||
|
consumers:
|
||||||
|
- model_training
|
||||||
|
- calibration_jobs
|
||||||
|
- diagnostics
|
||||||
|
|
||||||
|
forbidden_patterns:
|
||||||
|
- "읽기 모델을 쓰기 원장으로 사용"
|
||||||
|
- "원천 payload를 읽기 projection에 중복 저장"
|
||||||
|
- "직렬 UI 조회를 위해 원장 테이블을 직접 조인해 장기 유지"
|
||||||
|
|
||||||
|
expected_fields:
|
||||||
|
normalized_tables:
|
||||||
|
source_observation:
|
||||||
|
- observation_id
|
||||||
|
- observed_at
|
||||||
|
- instrument_id
|
||||||
|
- source_name
|
||||||
|
- source_version
|
||||||
|
- payload
|
||||||
|
- provenance
|
||||||
|
factor_observation:
|
||||||
|
- factor_observation_id
|
||||||
|
- observation_id
|
||||||
|
- factor_id
|
||||||
|
- factor_version
|
||||||
|
- observed_at
|
||||||
|
- numeric_value
|
||||||
|
- text_value
|
||||||
|
- gate
|
||||||
|
- provenance
|
||||||
|
decision_event:
|
||||||
|
- decision_id
|
||||||
|
- decision_key
|
||||||
|
- decided_at
|
||||||
|
- instrument_id
|
||||||
|
- action
|
||||||
|
- gate
|
||||||
|
- score
|
||||||
|
- source_version
|
||||||
|
- trace
|
||||||
|
- provenance
|
||||||
|
denormalized_view:
|
||||||
|
- decision_id
|
||||||
|
- decision_key
|
||||||
|
- decided_at
|
||||||
|
- instrument_id
|
||||||
|
- action
|
||||||
|
- decision_gate
|
||||||
|
- score
|
||||||
|
- source_version
|
||||||
|
- horizon_days
|
||||||
|
- realized_return
|
||||||
|
- benchmark_return
|
||||||
|
- excess_return
|
||||||
|
- outcome_class
|
||||||
|
- evaluation_gate
|
||||||
|
- factor_features
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "정규화는 쓰기 중복 제거와 provenance 보존이 목적이다."
|
||||||
|
- "역정규화는 학습/진단 편의용 projection으로만 허용한다."
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_PARITY_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
source_of_truth:
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FormulaEngine.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/ExitDecisions.cs
|
||||||
|
- src/dotnet/QuantEngine.Core/Domain/FactorCalculator.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FormulaEngineTests.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FactorCalculatorTests.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
|
||||||
|
goal: "Python reference와 .NET domain 결과를 데이터 기반 parity 계약으로 고정한다."
|
||||||
|
|
||||||
|
targets:
|
||||||
|
- target_id: formula_engine_timing
|
||||||
|
symbol: FormulaEngine.ComputeTimingDecision
|
||||||
|
tolerance:
|
||||||
|
numeric: 0
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FormulaEngineTests.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "timing action/reason이 reference와 동일"
|
||||||
|
|
||||||
|
- target_id: formula_engine_sell
|
||||||
|
symbol: FormulaEngine.ComputeSellDecision
|
||||||
|
tolerance:
|
||||||
|
numeric: 0
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FormulaEngineTests.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "sell action/ratio/validation이 reference와 동일"
|
||||||
|
|
||||||
|
- target_id: formula_engine_final
|
||||||
|
symbol: FormulaEngine.ComputeFinalDecision
|
||||||
|
tolerance:
|
||||||
|
numeric: 0
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FormulaEngineTests.cs
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "final action/priority/source가 reference와 동일"
|
||||||
|
|
||||||
|
- target_id: exit_stop_price
|
||||||
|
symbol: ExitDecisions.ComputeStopPriceCore
|
||||||
|
tolerance:
|
||||||
|
numeric: 0.0001
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "stop price within tolerance"
|
||||||
|
|
||||||
|
- target_id: exit_stop_ladder
|
||||||
|
symbol: ExitDecisions.ComputeStopActionLadder
|
||||||
|
tolerance:
|
||||||
|
numeric: 0
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "exit action ladder exact match"
|
||||||
|
|
||||||
|
- target_id: exit_heat_thresholds
|
||||||
|
symbol: ExitDecisions.ComputeDynamicHeatThresholds
|
||||||
|
tolerance:
|
||||||
|
numeric: 0
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/ParityTests/DomainParityTests.cs
|
||||||
|
pass_condition: "heat thresholds exact match"
|
||||||
|
|
||||||
|
- target_id: factor_calculator
|
||||||
|
symbol: FactorCalculator.CalculateFactors
|
||||||
|
tolerance:
|
||||||
|
numeric: 0.000001
|
||||||
|
text: exact
|
||||||
|
evidence:
|
||||||
|
- src/dotnet/QuantEngine.Core.Tests/FactorCalculatorTests.cs
|
||||||
|
pass_condition: "factor outputs stable and deterministic"
|
||||||
|
|
||||||
|
execution_notes:
|
||||||
|
- "Parity is a contract, not a guess."
|
||||||
|
- "Do not add new parity targets without updating reference fixtures and tolerances."
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_PROVENANCE_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "결정/팩터/수집 provenance payload를 표준화한다."
|
||||||
|
|
||||||
|
payloads:
|
||||||
|
- payload_id: factor_evidence
|
||||||
|
source: src/dotnet/QuantEngine.Application/Services/DecisionLearningService.cs
|
||||||
|
required_fields:
|
||||||
|
- FactorObservationId
|
||||||
|
- FactorId
|
||||||
|
- FactorVersion
|
||||||
|
- ObservedAt
|
||||||
|
- Gate
|
||||||
|
- Role
|
||||||
|
- SourceName
|
||||||
|
- PayloadJson
|
||||||
|
- ProvenanceJson
|
||||||
|
nullable_fields:
|
||||||
|
- NumericValue
|
||||||
|
- TextValue
|
||||||
|
pass_condition: "factor evidence payload가 누락 없이 기록됨"
|
||||||
|
|
||||||
|
- payload_id: decision_event
|
||||||
|
source: src/dotnet/QuantEngine.Application/Services/DecisionLearningService.cs
|
||||||
|
required_fields:
|
||||||
|
- decisionKey
|
||||||
|
- decidedAt
|
||||||
|
- instrumentId
|
||||||
|
- action
|
||||||
|
- gate
|
||||||
|
- sourceVersion
|
||||||
|
nullable_fields:
|
||||||
|
- score
|
||||||
|
- trace
|
||||||
|
- provenance
|
||||||
|
pass_condition: "decision event payload가 normalized store에 기록됨"
|
||||||
|
|
||||||
|
- payload_id: collection_audit
|
||||||
|
source: src/dotnet/QuantEngine.Application/Models/CollectionExecutionAudit.cs
|
||||||
|
required_fields:
|
||||||
|
- RunId
|
||||||
|
- State
|
||||||
|
- StartedAt
|
||||||
|
- SuccessCount
|
||||||
|
- ErrorCount
|
||||||
|
nullable_fields:
|
||||||
|
- FinishedAt
|
||||||
|
- Message
|
||||||
|
pass_condition: "collection audit payload가 append-only JSONL에 기록됨"
|
||||||
|
|
||||||
|
- payload_id: scheduler_audit
|
||||||
|
source: src/dotnet/QuantEngine.Web/Services/SchedulerModels.cs
|
||||||
|
required_fields:
|
||||||
|
- JobId
|
||||||
|
- RunId
|
||||||
|
- State
|
||||||
|
- StartedAt
|
||||||
|
nullable_fields:
|
||||||
|
- Reason
|
||||||
|
- FinishedAt
|
||||||
|
- ResourceKey
|
||||||
|
pass_condition: "scheduler audit payload가 append-only JSONL에 기록됨"
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "provenance payload는 구조를 표준화하되, 숫자 계산은 하지 않는다."
|
||||||
|
- "LLM은 payload value를 재계산하지 않는다."
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_READ_MODEL_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "운영 화면과 조회 API의 read model 경계를 분리한다."
|
||||||
|
|
||||||
|
read_models:
|
||||||
|
- model_id: dashboard_summary
|
||||||
|
purpose: "운영 대시보드 상태"
|
||||||
|
source: QuantEngine.Infrastructure.Repositories.CollectionRepository
|
||||||
|
consumers:
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs
|
||||||
|
fields:
|
||||||
|
- LastRunId
|
||||||
|
- LastRunAt
|
||||||
|
- SuccessCount
|
||||||
|
- ErrorCount
|
||||||
|
- SnapshotCount
|
||||||
|
staleness_budget: "5m"
|
||||||
|
- model_id: collection_runs
|
||||||
|
purpose: "최근 수집 실행 이력"
|
||||||
|
source: QuantEngine.Infrastructure.Repositories.CollectionRepository
|
||||||
|
consumers:
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs
|
||||||
|
fields:
|
||||||
|
- RunId
|
||||||
|
- State
|
||||||
|
- StartedAt
|
||||||
|
- FinishedAt
|
||||||
|
- SuccessCount
|
||||||
|
- ErrorCount
|
||||||
|
staleness_budget: "5m"
|
||||||
|
- model_id: price_history_summary
|
||||||
|
purpose: "가격 히스토리 요약"
|
||||||
|
source: QuantEngine.Infrastructure.Repositories.CollectionRepository
|
||||||
|
consumers:
|
||||||
|
- src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml.cs
|
||||||
|
- src/dotnet/QuantEngine.Web/Endpoints/CollectionEndpoints.cs
|
||||||
|
fields:
|
||||||
|
- Ticker
|
||||||
|
- Count
|
||||||
|
- FirstDate
|
||||||
|
- LastDate
|
||||||
|
staleness_budget: "15m"
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- "read model은 조회 전용이어야 한다."
|
||||||
|
- "운영 화면은 직접 원장 테이블을 조립하지 않는다."
|
||||||
|
- "쓰기 로직은 read model에 의존하지 않는다."
|
||||||
|
- "staleness_budget이 명시되지 않은 조회는 금지한다."
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "의도된 역정규화는 허용하되, 원장과 동일 테이블로 재사용하지 않는다."
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
formula_id: WBS_10_DOTNET_SCHEDULER_CONTRACT_V1
|
||||||
|
owner: QuantEngine
|
||||||
|
status: draft
|
||||||
|
goal: "스케줄러 상태 전이, 의존성, 재시도, 감사 추적을 표준화한다."
|
||||||
|
|
||||||
|
state_machine:
|
||||||
|
states:
|
||||||
|
- pending
|
||||||
|
- running
|
||||||
|
- succeeded
|
||||||
|
- failed
|
||||||
|
- retrying
|
||||||
|
- blocked
|
||||||
|
allowed_transitions:
|
||||||
|
pending: [running, blocked]
|
||||||
|
running: [succeeded, failed, retrying, blocked]
|
||||||
|
failed: [retrying, blocked]
|
||||||
|
retrying: [running, failed, blocked]
|
||||||
|
succeeded: []
|
||||||
|
blocked: []
|
||||||
|
|
||||||
|
job_definitions:
|
||||||
|
- job_id: daily-collection
|
||||||
|
cron: "0 9 * * *"
|
||||||
|
lease_owner: collection
|
||||||
|
timeout_policy: "2h"
|
||||||
|
dependency: gather-trading-data
|
||||||
|
- job_id: hourly-price-update
|
||||||
|
cron: "0 9,11,13,15 * * 1-5"
|
||||||
|
lease_owner: price-update
|
||||||
|
timeout_policy: "30m"
|
||||||
|
dependency: price-feed
|
||||||
|
- job_id: weekly-report
|
||||||
|
cron: "0 17 * * 5"
|
||||||
|
lease_owner: report
|
||||||
|
timeout_policy: "1h"
|
||||||
|
dependency: report-generator
|
||||||
|
- job_id: monthly-optimization
|
||||||
|
cron: "0 2 1 * *"
|
||||||
|
lease_owner: optimization
|
||||||
|
timeout_policy: "3h"
|
||||||
|
dependency: optimizer
|
||||||
|
|
||||||
|
audit_fields:
|
||||||
|
- JobId
|
||||||
|
- RunId
|
||||||
|
- State
|
||||||
|
- StartedAt
|
||||||
|
- FinishedAt
|
||||||
|
- ResourceKey
|
||||||
|
- Reason
|
||||||
|
|
||||||
|
idempotency:
|
||||||
|
required: true
|
||||||
|
key_pattern: "{job_id}:{resource_key}:{yyyyMMddHHmm}"
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- "상태 전이와 감사 추적은 append-only JSONL로 남긴다."
|
||||||
|
- "실행 재개는 retrying 이후에만 허용한다."
|
||||||
|
- "숫자 계산은 여기서 하지 않는다."
|
||||||
@@ -0,0 +1,516 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// QuantEngine Database Schema (DBML)
|
||||||
|
// DbUp 마이그레이션(V1~V5)과 1:1 동기화 — 마이그레이션 추가 시 이 파일도 반드시 갱신
|
||||||
|
// (CLAUDE.md 규칙: schema 변경 → DBML + 문서 동기화)
|
||||||
|
//
|
||||||
|
// 참고: Hangfire 스키마는 Hangfire.PostgreSql 라이브러리가 자동 생성
|
||||||
|
// (DbUp 마이그레이션으로 관리하지 않음, 여기서도 제외)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Project quantengine {
|
||||||
|
database_type: 'PostgreSQL'
|
||||||
|
Note: '''
|
||||||
|
QuantEngine v0.1 데이터베이스 스키마.
|
||||||
|
세 개 스키마로 구성:
|
||||||
|
- quantengine: 핵심 KIS API 토큰, 사용자 계정, 수집 파이프라인 데이터
|
||||||
|
- engine_history: 팩터 계산 이력, 시장 데이터 이력, 의사결정 이력
|
||||||
|
- (생략) hangfire: Hangfire 백그라운드 잡 관리 (auto-created)
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Schema: quantengine (V1 + V2)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
TableGroup "quantengine" {
|
||||||
|
kis_tokens
|
||||||
|
workspace_account
|
||||||
|
workspace_session
|
||||||
|
collection_runs
|
||||||
|
collection_snapshots
|
||||||
|
collection_source_errors
|
||||||
|
settings
|
||||||
|
account_snapshot
|
||||||
|
workspace_meta
|
||||||
|
workspace_change_log
|
||||||
|
workspace_approval_v2
|
||||||
|
workspace_lock
|
||||||
|
kis_collection_runs
|
||||||
|
kis_collection_snapshots
|
||||||
|
kis_collection_errors
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.kis_tokens {
|
||||||
|
account TEXT [pk, note: "KIS 계정 모드 (real/mock)"]
|
||||||
|
access_token TEXT [not null, note: "KIS 토큰"]
|
||||||
|
expires_at TEXT [not null, note: "만료 시각 (ISO 8601)"]
|
||||||
|
updated_at TEXT [not null, note: "마지막 갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
Note: "KIS Open API 인증 토큰 캐시"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_account {
|
||||||
|
ordinal INT [not null, note: "순서 인덱스"]
|
||||||
|
username TEXT [pk, note: "로그인 ID"]
|
||||||
|
password_hash TEXT [not null, note: "BCrypt 또는 SHA-256 해시 (자동 마이그레이션 가능)"]
|
||||||
|
role TEXT [not null, default: "'Admin'", note: "역할 (Admin)"]
|
||||||
|
is_active TEXT [not null, default: "'true'", note: "활성 상태 (true/false)"]
|
||||||
|
created_at TEXT [not null, note: "생성 시각 (ISO 8601)"]
|
||||||
|
updated_at TEXT [not null, note: "갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(is_active, username) [name: "idx_workspace_account_active"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "Admin UI 사용자 계정"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_session {
|
||||||
|
session_token_hash TEXT [pk, note: "세션 토큰 해시"]
|
||||||
|
username TEXT [not null, note: "사용자명"]
|
||||||
|
role TEXT [not null, default: "'Admin'", note: "역할"]
|
||||||
|
created_at TEXT [not null, note: "세션 생성 시각 (ISO 8601)"]
|
||||||
|
expires_at TEXT [not null, note: "만료 시각 (ISO 8601)"]
|
||||||
|
revoked_at TEXT [note: "취소 시각 (ISO 8601), NULL이면 활성"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(username, expires_at) [name: "idx_workspace_session_username"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "세션 관리 (쿠키 기반 인증)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.collection_runs {
|
||||||
|
run_id TEXT [pk, note: "수집 실행 ID (예: api-20260712-120000)"]
|
||||||
|
collector_name TEXT [not null, note: "수집기 이름"]
|
||||||
|
started_at TEXT [not null, note: "시작 시각 (ISO 8601)"]
|
||||||
|
finished_at TEXT [note: "종료 시각 (ISO 8601)"]
|
||||||
|
status TEXT [not null, note: "상태 (RUNNING/COMPLETED/FAILED)"]
|
||||||
|
input_source TEXT [note: "입력 소스 경로"]
|
||||||
|
output_json_path TEXT [note: "출력 JSON 파일 경로"]
|
||||||
|
output_db_path TEXT [note: "출력 DB 경로"]
|
||||||
|
notes TEXT [note: "메모"]
|
||||||
|
created_at TIMESTAMP [default: "CURRENT_TIMESTAMP", note: "DB 기록 시각"]
|
||||||
|
|
||||||
|
Note: "데이터 수집 실행 기록 (레거시, V2의 kis_collection_runs 참조)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.collection_snapshots {
|
||||||
|
run_id TEXT [not null, note: "수집 실행 ID"]
|
||||||
|
dataset_name TEXT [not null, note: "데이터셋명"]
|
||||||
|
ticker TEXT [not null, note: "종목코드 (예: 005930)"]
|
||||||
|
name TEXT [note: "종목명"]
|
||||||
|
sector TEXT [note: "업종"]
|
||||||
|
as_of_date TEXT [note: "기준 일자"]
|
||||||
|
source_priority TEXT [note: "소스 우선순위"]
|
||||||
|
source_status TEXT [note: "소스 상태"]
|
||||||
|
payload_json TEXT [not null, note: "정규화된 데이터 (JSON)"]
|
||||||
|
provenance_json TEXT [not null, note: "출처 정보 (JSON)"]
|
||||||
|
created_at TIMESTAMP [default: "CURRENT_TIMESTAMP", note: "DB 기록 시각"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(run_id, dataset_name, ticker) [pk]
|
||||||
|
(ticker, created_at) [name: "idx_collection_snapshots_ticker_time"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "수집 스냅샷 (레거시, V2의 kis_collection_snapshots 참조)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.collection_source_errors {
|
||||||
|
run_id TEXT [not null, note: "수집 실행 ID"]
|
||||||
|
ticker TEXT [note: "종목코드"]
|
||||||
|
source_name TEXT [not null, note: "소스명"]
|
||||||
|
error_kind TEXT [not null, note: "에러 타입"]
|
||||||
|
error_message TEXT [not null, note: "에러 메시지"]
|
||||||
|
payload_json TEXT [note: "에러 상세 (JSON)"]
|
||||||
|
created_at TIMESTAMP [default: "CURRENT_TIMESTAMP", note: "DB 기록 시각"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(run_id, source_name) [name: "idx_collection_source_errors_run"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "수집 중 발생한 에러 기록 (레거시)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.settings {
|
||||||
|
ordinal INT [not null, note: "순서 인덱스"]
|
||||||
|
key TEXT [pk, note: "설정 키"]
|
||||||
|
value_json TEXT [not null, note: "값 (JSON)"]
|
||||||
|
note TEXT [not null, default: "''", note: "설명"]
|
||||||
|
updated_at TEXT [not null, note: "갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
Note: "애플리케이션 설정 저장소"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.account_snapshot {
|
||||||
|
ordinal INT [not null, note: "순서 인덱스"]
|
||||||
|
row_json TEXT [not null, note: "계정 데이터 (JSON)"]
|
||||||
|
captured_at TEXT [not null, default: "''", note: "캡처 시각 (ISO 8601)"]
|
||||||
|
account TEXT [not null, default: "''", note: "계정"]
|
||||||
|
account_type TEXT [not null, default: "''", note: "계정 타입"]
|
||||||
|
ticker TEXT [not null, default: "''", note: "종목코드"]
|
||||||
|
name TEXT [not null, default: "''", note: "이름"]
|
||||||
|
parse_status TEXT [not null, default: "''", note: "파싱 상태"]
|
||||||
|
user_confirmed TEXT [not null, default: "''", note: "사용자 확인 여부"]
|
||||||
|
updated_at TEXT [not null, note: "갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(captured_at) [name: "idx_account_snapshot_captured_at"]
|
||||||
|
(ticker) [name: "idx_account_snapshot_ticker"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "계정 스냅샷 저장소"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_meta {
|
||||||
|
key TEXT [pk, note: "메타 키"]
|
||||||
|
value_json TEXT [not null, note: "값 (JSON)"]
|
||||||
|
|
||||||
|
Note: "워크스페이스 메타데이터"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_change_log {
|
||||||
|
id SERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
domain TEXT [not null, note: "도메인"]
|
||||||
|
action TEXT [not null, note: "액션 (create/update/delete)"]
|
||||||
|
target_ref TEXT [not null, default: "''", note: "대상 참조"]
|
||||||
|
actor TEXT [not null, default: "'system'", note: "액터 (사용자/시스템)"]
|
||||||
|
note TEXT [not null, default: "''", note: "메모"]
|
||||||
|
before_json TEXT [not null, default: "'null'", note: "변경 전 값 (JSON)"]
|
||||||
|
after_json TEXT [not null, default: "'null'", note: "변경 후 값 (JSON)"]
|
||||||
|
created_at TEXT [not null, note: "기록 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
Note: "변경 로그"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_approval_v2 {
|
||||||
|
domain TEXT [not null, note: "도메인"]
|
||||||
|
target_ref TEXT [not null, default: "'*'", note: "대상 참조"]
|
||||||
|
status TEXT [not null, note: "승인 상태"]
|
||||||
|
approved_by TEXT [not null, default: "''", note: "승인자"]
|
||||||
|
approved_at TEXT [not null, default: "''", note: "승인 시각 (ISO 8601)"]
|
||||||
|
note TEXT [not null, default: "''", note: "메모"]
|
||||||
|
updated_at TEXT [not null, note: "갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(domain, target_ref) [pk]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "승인 워크플로우"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.workspace_lock {
|
||||||
|
domain TEXT [not null, note: "도메인"]
|
||||||
|
target_ref TEXT [not null, default: "''", note: "대상 참조"]
|
||||||
|
locked_by TEXT [not null, default: "''", note: "잠금 사용자"]
|
||||||
|
reason TEXT [not null, default: "''", note: "잠금 사유"]
|
||||||
|
locked_at TEXT [not null, note: "잠금 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(domain, target_ref) [pk]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "동시성 제어용 잠금"
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// V2: KIS 수집 파이프라인 (kis_collection_*)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Table quantengine.kis_collection_runs {
|
||||||
|
run_id TEXT [pk, note: "수집 실행 ID"]
|
||||||
|
status TEXT [not null, note: "상태: RUNNING / COMPLETED / COMPLETED_WITH_ERRORS / FAILED"]
|
||||||
|
started_at TEXT [not null, note: "시작 시각 (ISO 8601 KST)"]
|
||||||
|
finished_at TEXT [note: "종료 시각 (ISO 8601 KST)"]
|
||||||
|
total_snapshots INTEGER [note: "성공한 스냅샷 수"]
|
||||||
|
total_errors INTEGER [note: "발생한 에러 수"]
|
||||||
|
updated_at TEXT [not null, note: "마지막 갱신 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(started_at) [name: "idx_kis_runs_started_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "KIS API 수집 실행 기록"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.kis_collection_snapshots {
|
||||||
|
run_id TEXT [not null, note: "수집 실행 ID"]
|
||||||
|
dataset_name TEXT [note: "데이터셋명 (예: data_feed)"]
|
||||||
|
ticker TEXT [not null, note: "종목코드 (예: 005930)"]
|
||||||
|
source_name TEXT [not null, note: "데이터 소스 (kis_open_api 등)"]
|
||||||
|
payload_json TEXT [not null, note: "정규화된 수집 데이터 (JSON)"]
|
||||||
|
captured_at TEXT [not null, note: "캡처 시각 (ISO 8601 KST)"]
|
||||||
|
created_at TEXT [not null, note: "DB 기록 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(run_id, ticker, source_name) [pk]
|
||||||
|
(ticker) [name: "idx_kis_snapshots_ticker"]
|
||||||
|
(captured_at) [name: "idx_kis_snapshots_captured_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "KIS API 수집 스냅샷 (시계열 데이터)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.kis_collection_errors {
|
||||||
|
id SERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
run_id TEXT [not null, note: "수집 실행 ID"]
|
||||||
|
source_name TEXT [not null, note: "데이터 소스"]
|
||||||
|
error_kind TEXT [not null, note: "에러 타입 (예: HttpRequestException)"]
|
||||||
|
error_message TEXT [note: "에러 메시지"]
|
||||||
|
ticker TEXT [note: "종목코드 (해당하면)"]
|
||||||
|
created_at TEXT [not null, note: "DB 기록 시각 (ISO 8601)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(run_id) [name: "idx_kis_errors_run_id"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "KIS API 수집 중 발생한 에러"
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Schema: engine_history (V3)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
TableGroup "engine_history" {
|
||||||
|
market_raw_history
|
||||||
|
factor_version_history
|
||||||
|
factor_output_history
|
||||||
|
decision_result_history
|
||||||
|
market_vs_engine_gap_history
|
||||||
|
source_observation
|
||||||
|
factor_definition
|
||||||
|
factor_observation
|
||||||
|
decision_event
|
||||||
|
decision_factor_evidence
|
||||||
|
outcome_evaluation
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.market_raw_history {
|
||||||
|
id BIGSERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
source_id TEXT [not null, note: "소스 ID"]
|
||||||
|
observed_at TEXT [not null, note: "관측 시각 (ISO 8601)"]
|
||||||
|
source_name TEXT [not null, note: "소스명 (kis_open_api 등)"]
|
||||||
|
instrument_id TEXT [not null, note: "상품 ID (종목코드 등)"]
|
||||||
|
field_name TEXT [not null, note: "필드명 (현재가, 종가 등)"]
|
||||||
|
field_value TEXT [not null, note: "필드값 (문자열)"]
|
||||||
|
unit TEXT [not null, note: "단위 (원, % 등)"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb", note: "출처 메타데이터 (JSON)"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()", note: "DB 기록 시각 (UTC)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(created_at) [name: "idx_market_raw_history_created_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "시장 데이터 원본 이력 (정규화 전)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.factor_version_history {
|
||||||
|
id BIGSERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
factor_id TEXT [not null, note: "팩터 ID (예: momentum_ss001)"]
|
||||||
|
factor_version TEXT [not null, note: "팩터 버전 (예: v1.0.0)"]
|
||||||
|
effective_from TEXT [not null, note: "유효 시작 일자 (YYYYMMDD)"]
|
||||||
|
effective_to TEXT [not null, note: "유효 종료 일자 (YYYYMMDD)"]
|
||||||
|
formula_id TEXT [not null, note: "계산식 ID"]
|
||||||
|
source_version TEXT [not null, note: "소스 버전"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb", note: "출처 메타데이터 (JSON)"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()", note: "DB 기록 시각 (UTC)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(created_at) [name: "idx_factor_version_history_created_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "팩터 버전 관리 이력"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.factor_output_history {
|
||||||
|
id BIGSERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
factor_output_id TEXT [not null, note: "팩터 출력 ID"]
|
||||||
|
observed_at TEXT [not null, note: "관측 일자 (YYYYMMDD)"]
|
||||||
|
factor_id TEXT [not null, note: "팩터 ID"]
|
||||||
|
factor_version TEXT [not null, note: "팩터 버전"]
|
||||||
|
output_value TEXT [not null, note: "출력값 (문자열)"]
|
||||||
|
output_gate TEXT [not null, note: "게이트 (PASS/FAIL/WARN)"]
|
||||||
|
source_version TEXT [not null, note: "소스 버전"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb", note: "출처 메타데이터 (JSON)"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()", note: "DB 기록 시각 (UTC)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(created_at) [name: "idx_factor_output_history_created_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "팩터 계산 결과 이력"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.decision_result_history {
|
||||||
|
id BIGSERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
decision_id TEXT [not null, note: "의사결정 ID"]
|
||||||
|
decided_at TEXT [not null, note: "의사결정 일자 (YYYYMMDD)"]
|
||||||
|
instrument_id TEXT [not null, note: "상품 ID (종목코드 등)"]
|
||||||
|
action TEXT [not null, note: "액션 (BUY/SELL/HOLD)"]
|
||||||
|
gate TEXT [not null, note: "게이트 (PASS/FAIL)"]
|
||||||
|
score TEXT [not null, note: "스코어 (문자열)"]
|
||||||
|
source_version TEXT [not null, note: "소스 버전"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb", note: "출처 메타데이터 (JSON)"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()", note: "DB 기록 시각 (UTC)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(created_at) [name: "idx_decision_result_history_created_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "의사결정 결과 이력"
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.market_vs_engine_gap_history {
|
||||||
|
id BIGSERIAL [pk, note: "자동 증가 ID"]
|
||||||
|
gap_id TEXT [not null, note: "갭 ID"]
|
||||||
|
observed_at TEXT [not null, note: "관측 일자 (YYYYMMDD)"]
|
||||||
|
instrument_id TEXT [not null, note: "상품 ID"]
|
||||||
|
metric_name TEXT [not null, note: "지표명"]
|
||||||
|
market_value TEXT [not null, note: "시장값"]
|
||||||
|
engine_value TEXT [not null, note: "엔진값"]
|
||||||
|
gap_value TEXT [not null, note: "갭값 (절대값)"]
|
||||||
|
gap_pct TEXT [not null, note: "갭 백분율 (%)"]
|
||||||
|
source_version TEXT [not null, note: "소스 버전"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb", note: "출처 메타데이터 (JSON)"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()", note: "DB 기록 시각 (UTC)"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(created_at) [name: "idx_market_vs_engine_gap_history_created_at"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: "시장 데이터 vs 엔진 계산 갭 분석 이력"
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Schema: engine_history (V5 normalized learning history)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Table quantengine.price_history_daily {
|
||||||
|
ticker TEXT [not null]
|
||||||
|
trade_date DATE [not null]
|
||||||
|
open NUMERIC [not null]
|
||||||
|
high NUMERIC [not null]
|
||||||
|
low NUMERIC [not null]
|
||||||
|
close NUMERIC [not null]
|
||||||
|
volume BIGINT [not null]
|
||||||
|
source TEXT [not null]
|
||||||
|
collected_at TIMESTAMPTZ [not null, default: "NOW()"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(ticker, trade_date) [pk]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Table quantengine.macro_history_daily {
|
||||||
|
symbol TEXT [not null]
|
||||||
|
trade_date DATE [not null]
|
||||||
|
value NUMERIC [not null]
|
||||||
|
source TEXT [not null]
|
||||||
|
collected_at TIMESTAMPTZ [not null, default: "NOW()"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(symbol, trade_date) [pk]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.source_observation {
|
||||||
|
observation_id UUID [pk]
|
||||||
|
observed_at TIMESTAMPTZ [not null]
|
||||||
|
instrument_id TEXT [not null]
|
||||||
|
source_name TEXT [not null]
|
||||||
|
source_version TEXT [not null]
|
||||||
|
payload JSONB [not null]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.factor_definition {
|
||||||
|
factor_id TEXT [not null]
|
||||||
|
factor_version TEXT [not null]
|
||||||
|
formula_id TEXT [not null]
|
||||||
|
effective_from TIMESTAMPTZ [not null]
|
||||||
|
effective_to TIMESTAMPTZ
|
||||||
|
definition JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(factor_id, factor_version) [pk]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.factor_observation {
|
||||||
|
factor_observation_id UUID [pk]
|
||||||
|
observation_id UUID [not null]
|
||||||
|
factor_id TEXT [not null]
|
||||||
|
factor_version TEXT [not null]
|
||||||
|
observed_at TIMESTAMPTZ [not null]
|
||||||
|
numeric_value NUMERIC
|
||||||
|
text_value TEXT
|
||||||
|
gate TEXT [not null]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.decision_event {
|
||||||
|
decision_id UUID [pk]
|
||||||
|
decision_key TEXT [not null, unique]
|
||||||
|
decided_at TIMESTAMPTZ [not null]
|
||||||
|
instrument_id TEXT [not null]
|
||||||
|
action TEXT [not null]
|
||||||
|
gate TEXT [not null]
|
||||||
|
score NUMERIC
|
||||||
|
source_version TEXT [not null]
|
||||||
|
trace JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
created_at TIMESTAMPTZ [not null, default: "NOW()"]
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.decision_factor_evidence {
|
||||||
|
decision_id UUID [not null]
|
||||||
|
factor_observation_id UUID [not null]
|
||||||
|
role TEXT [not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(decision_id, factor_observation_id) [pk]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Table engine_history.outcome_evaluation {
|
||||||
|
evaluation_id UUID [pk]
|
||||||
|
decision_id UUID [not null]
|
||||||
|
horizon_days INT [not null]
|
||||||
|
evaluated_at TIMESTAMPTZ [not null]
|
||||||
|
realized_return NUMERIC
|
||||||
|
benchmark_return NUMERIC
|
||||||
|
excess_return NUMERIC
|
||||||
|
outcome_class TEXT [not null]
|
||||||
|
evaluation_gate TEXT [not null]
|
||||||
|
provenance JSONB [not null, default: "'{}'::jsonb"]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(decision_id, horizon_days) [unique]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Relationships (Logical, not enforced as FKs in DDL)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Ref: quantengine.kis_collection_snapshots.run_id > quantengine.kis_collection_runs.run_id {
|
||||||
|
// logical relationship: snapshots belong to a run
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref: quantengine.kis_collection_errors.run_id > quantengine.kis_collection_runs.run_id {
|
||||||
|
// logical relationship: errors belong to a run
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref: quantengine.workspace_session.username > quantengine.workspace_account.username {
|
||||||
|
// logical relationship: session belongs to a user
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref: engine_history.factor_observation.observation_id > engine_history.source_observation.observation_id
|
||||||
|
Ref: engine_history.factor_observation.(factor_id, factor_version) > engine_history.factor_definition.(factor_id, factor_version)
|
||||||
|
Ref: engine_history.decision_factor_evidence.decision_id > engine_history.decision_event.decision_id
|
||||||
|
Ref: engine_history.decision_factor_evidence.factor_observation_id > engine_history.factor_observation.factor_observation_id
|
||||||
|
Ref: engine_history.outcome_evaluation.decision_id > engine_history.decision_event.decision_id
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# QuantEngine 수집 파이프라인 (KIS API)
|
||||||
|
|
||||||
|
## 1. 수집 실행 상태 전이도 (State Diagram)
|
||||||
|
|
||||||
|
KIS 데이터 수집 실행(kis_collection_runs)의 상태 흐름. 상태값은 KisDataCollectionOrchestrator 에서 정의:
|
||||||
|
- `RUNNING`: 수집 진행 중
|
||||||
|
- `COMPLETED`: 모든 스냅샷 수집 완료 (에러 없음, `total_errors == 0`)
|
||||||
|
- `COMPLETED_WITH_ERRORS`: 부분 수집 완료 (에러 발생, `total_errors > 0`이지만 일부 성공)
|
||||||
|
- `FAILED`: 전체 실패 (예외 발생, 데이터 미적재)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> RUNNING: 수집 시작<br/>(RunCollectionAsync)
|
||||||
|
RUNNING --> COMPLETED: 완료 & error_count==0
|
||||||
|
RUNNING --> COMPLETED_WITH_ERRORS: 완료 & error_count>0
|
||||||
|
RUNNING --> FAILED: 예외 발생
|
||||||
|
COMPLETED --> [*]
|
||||||
|
COMPLETED_WITH_ERRORS --> [*]
|
||||||
|
FAILED --> [*]
|
||||||
|
```
|
||||||
|
|
||||||
|
**상태 전이 조건** (KisDataCollectionOrchestrator.cs 라인 104-105):
|
||||||
|
- `error_count == 0` → `COMPLETED`
|
||||||
|
- `error_count > 0` → `COMPLETED_WITH_ERRORS`
|
||||||
|
- 예외(Exception) → `FAILED`
|
||||||
|
|
||||||
|
**성공 기준** (CLAUDE.md "Collection Run Success Criteria"):
|
||||||
|
- Success: `status == "COMPLETED"` (NOT failed)
|
||||||
|
- Partial Success: `status == "COMPLETED"` + `total_snapshots > 0` + `total_errors > 0`
|
||||||
|
- Failure: `status == "FAILED"` OR `total_snapshots == 0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 수집 파이프라인 흐름도 (Flowchart)
|
||||||
|
|
||||||
|
KIS API 데이터 수집의 전체 흐름. 두 개의 트리거:
|
||||||
|
1. **Hangfire 정기 작업**: 매일 09:00 에 자동 실행
|
||||||
|
2. **API 수동 트리거**: POST /api/collection/run (쿠키 기반 인증)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A["Hangfire daily-collection<br/>(09:00 KST)"]
|
||||||
|
B["POST /api/collection/run<br/>(Cookie Auth)"]
|
||||||
|
|
||||||
|
A --> C["IServiceScopeFactory.CreateScope<br/>(resolve ICollectionOrchestrator)"]
|
||||||
|
B --> C
|
||||||
|
|
||||||
|
C --> D["KisDataCollectionOrchestrator.RunCollectionAsync<br/>(tickers: [005930, 000660, ...])"]
|
||||||
|
|
||||||
|
D --> E["Per-ticker 루프"]
|
||||||
|
E --> F["KisApiPriceSource.GetPriceDataAsync<br/>(ticker, account)"]
|
||||||
|
F --> G["PriceDataNormalizer.NormalizeCollectionRow<br/>(seedRow, kisResult)"]
|
||||||
|
G --> H["CollectionRepository.SaveSnapshot<br/>(kis_collection_snapshots)"]
|
||||||
|
G --> I["CollectionRepository.SaveError<br/>(kis_collection_errors, on exception)"]
|
||||||
|
|
||||||
|
H --> J{루프 끝?}
|
||||||
|
I --> J
|
||||||
|
J -->|Yes| K["CollectionRepository.SaveRun<br/>(kis_collection_runs)"]
|
||||||
|
J -->|No| E
|
||||||
|
|
||||||
|
K --> L["파일 출력:<br/>Temp/kis_dotnet_collection_v1.json"]
|
||||||
|
L --> M["Serilog 로그:<br/>src/dotnet/.../logs/"]
|
||||||
|
|
||||||
|
M --> N["Admin UI: /Admin/Collection<br/>(CollectionRepository 읽기)"]
|
||||||
|
N --> O["대시보드 표시:<br/>상태, 스냅샷 수, 에러"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**데이터 흐름**:
|
||||||
|
1. **입력**: Hangfire 스케줄 or API 수동 요청
|
||||||
|
2. **오케스트레이션**: ICollectionOrchestrator 스코프 생성
|
||||||
|
3. **수집**: KIS Open API 호출 → PriceDataNormalizer → DB 저장
|
||||||
|
4. **출력**:
|
||||||
|
- kis_collection_runs: 실행 메타데이터 (run_id, status, total_snapshots, total_errors)
|
||||||
|
- kis_collection_snapshots: 종목별 가격 데이터 (JSON payload)
|
||||||
|
- kis_collection_errors: 에러 기록
|
||||||
|
- Temp/kis_dotnet_collection_v1.json: 수집 결과 요약 (formula_id, gate, run_id, summary)
|
||||||
|
- Serilog 로그: 런타임 로그 (src/dotnet/QuantEngine.Web/logs/)
|
||||||
|
5. **표시**: Admin UI에서 CollectionRepository API 호출 → kis_collection_* 읽기 → Dashboard 렌더링
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. WBS 증거 검증 시퀀스도 (Sequence Diagram)
|
||||||
|
|
||||||
|
작업 완료 증거를 자동 검증하는 파이프라인. 도구: `verify_wbs_task_v1.py` (증거 수집) + `validate_quant_engine_wbs_v1.py` (CI에서 재검증).
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
Developer->>verify_wbs_task_v1.py: python verify_wbs_task_v1.py --task QE-M1-01<br/>(또는 --run-commands)
|
||||||
|
verify_wbs_task_v1.py->>+spec/60_quant_engine_wbs.yaml: load spec
|
||||||
|
spec/60_quant_engine_wbs.yaml-->>-verify_wbs_task_v1.py: meta + tasks[QE-M1-01]
|
||||||
|
|
||||||
|
Note over verify_wbs_task_v1.py: evidence_checks 선언형 해석
|
||||||
|
|
||||||
|
alt pg_query 체크
|
||||||
|
verify_wbs_task_v1.py->>+PostgreSQL: SELECT ... (WHERE 절)
|
||||||
|
PostgreSQL-->>-verify_wbs_task_v1.py: 스칼라 결과 또는 행
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: expect{min,max,equals} 비교
|
||||||
|
end
|
||||||
|
|
||||||
|
alt log_pattern 체크
|
||||||
|
verify_wbs_task_v1.py->>+src/dotnet/.../logs/: file_glob 매칭
|
||||||
|
src/dotnet/.../logs/-->>-verify_wbs_task_v1.py: 로그 라인
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 정규식 패턴 검사<br/>(min_matches, max_age_hours)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt json_gate 체크
|
||||||
|
verify_wbs_task_v1.py->>+Temp/kis_dotnet_collection_v1.json: read JSON
|
||||||
|
Temp/kis_dotnet_collection_v1.json-->>-verify_wbs_task_v1.py: payload
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 점 표기 경로(dot notation)<br/>+ 값 비교 (>=N 지원)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt file_exists 체크
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: paths[] 존재 확인<br/>(min_bytes 검증)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt playwright_report 체크
|
||||||
|
verify_wbs_task_v1.py->>+tests/e2e/playwright-report.json: read report
|
||||||
|
tests/e2e/playwright-report.json-->>-verify_wbs_task_v1.py: suites[].specs[]
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: spec_file 매칭<br/>(passed_min, failed)
|
||||||
|
end
|
||||||
|
|
||||||
|
verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 모든 체크 결과 종합<br/>(gate = ALL PASS? → PASS : FAIL)
|
||||||
|
|
||||||
|
verify_wbs_task_v1.py->>+Temp/evidence/QE-M1-01/: mkdir
|
||||||
|
verify_wbs_task_v1.py->>Temp/evidence/QE-M1-01/verdict.json: write verdict<br/>(task_id, gate, checks[])
|
||||||
|
verify_wbs_task_v1.py->>Temp/evidence/QE-M1-01/: save raw evidence<br/>(pg_query_n.json, log_excerpt.txt, ...)
|
||||||
|
|
||||||
|
verify_wbs_task_v1.py->>+runtime/lineage_events.jsonl: append event<br/>(node_id, gate, timestamp)
|
||||||
|
|
||||||
|
Developer<<--verify_wbs_task_v1.py: exit 0 (gate=PASS)<br/>or exit 1 (gate=FAIL)
|
||||||
|
|
||||||
|
Note over Developer: 선택: --run-commands 플래그<br/>verification_commands[] 실행
|
||||||
|
|
||||||
|
Developer->>+validate_quant_engine_wbs_v1.py: (CI) python validate_quant_engine_wbs_v1.py
|
||||||
|
validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: spec load
|
||||||
|
validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: tasks[status==DONE] 필터
|
||||||
|
validate_quant_engine_wbs_v1.py->>+Temp/evidence/*/verdict.json: load all verdicts
|
||||||
|
Temp/evidence/*/verdict.json-->>-validate_quant_engine_wbs_v1.py: gate 값
|
||||||
|
validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: gate=FAIL? → CI FAIL
|
||||||
|
validate_quant_engine_wbs_v1.py->>+Temp/quant_engine_wbs_v1.json: write summary
|
||||||
|
Developer<<--validate_quant_engine_wbs_v1.py: exit 0 (모두 PASS)<br/>or exit 1 (일부 FAIL)
|
||||||
|
```
|
||||||
|
|
||||||
|
**검증 프로세스 상세**:
|
||||||
|
|
||||||
|
| 단계 | 역할 | 산출물 |
|
||||||
|
|------|------|--------|
|
||||||
|
| **1. 스펙 로드** | verify_wbs_task_v1.py | spec/60_quant_engine_wbs.yaml |
|
||||||
|
| **2. 증거 체크 실행** | 선언형 evidence_checks[] | pg_query / log_pattern / json_gate / file_exists / playwright_report |
|
||||||
|
| **3. 게이트 결정** | 모든 체크 PASS? | gate = PASS or FAIL |
|
||||||
|
| **4. 증거 저장** | Temp/evidence/<TASK_ID>/ | verdict.json + 원시 증거 |
|
||||||
|
| **5. 계보 로깅** | runtime/lineage_events.jsonl | node_id, gate, timestamp |
|
||||||
|
| **6. CI 재검증** | validate_quant_engine_wbs_v1.py | status=DONE 작업만 재검증 |
|
||||||
|
|
||||||
|
**주요 특징**:
|
||||||
|
- **선언형 검증**: 체크 로직을 YAML에 기술 (하드코딩 최소화)
|
||||||
|
- **원시 증거 보존**: 각 체크의 상세 결과를 JSON/텍스트로 저장
|
||||||
|
- **완료 주장 차단**: "완료했다"는 수동 선언 불가 → verdict.json gate=PASS만 인정
|
||||||
|
- **CI 편입**: validate_quant_engine_wbs_v1.py가 release DAG의 노드로 동작
|
||||||
|
- **멀티 트리거**: 단일 작업 검증 (--task) 또는 전체 검증 (CI)
|
||||||
|
|
||||||
|
**검증 체크 타입 참고** (spec/60_quant_engine_wbs.yaml "evidence_check_types"):
|
||||||
|
- **pg_query**: PostgreSQL 스칼라 결과 비교 (min/max/equals)
|
||||||
|
- **log_pattern**: 로그 파일 정규식 매칭 (min_matches, max_age_hours)
|
||||||
|
- **json_gate**: JSON 아티팩트 키-값 검사 (점 표기 경로, >=N 비교)
|
||||||
|
- **file_exists**: 파일 존재 + 크기 검증 (min_bytes)
|
||||||
|
- **playwright_report**: Playwright 리포트 테스트 결과 (passed_min, failed)
|
||||||
+10
-1
@@ -52,7 +52,16 @@
|
|||||||
"validate-engine-strict": "python tools/run_release_dag_v3.py --mode release --strict",
|
"validate-engine-strict": "python tools/run_release_dag_v3.py --mode release --strict",
|
||||||
"validate-behavioral-coverage": "python tools/validate_behavioral_coverage_v1.py --strict",
|
"validate-behavioral-coverage": "python tools/validate_behavioral_coverage_v1.py --strict",
|
||||||
"validate-engine-integrity": "python tools/run_release_dag_v3.py --mode release --strict",
|
"validate-engine-integrity": "python tools/run_release_dag_v3.py --mode release --strict",
|
||||||
"render-report-json": "dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -- report --packet=Temp/final_decision_packet_active.json --out=Temp/operational_report.json"
|
"render-report-json": "dotnet run --project src/dotnet/QuantEngine.Tools/QuantEngine.Tools.csproj -- report --packet=Temp/final_decision_packet_active.json --out=Temp/operational_report.json",
|
||||||
|
"verify:task": "python tools/verify_wbs_task_v1.py --task",
|
||||||
|
"collect:remote-evidence": "python tools/collect_remote_wbs_evidence_v1.py",
|
||||||
|
"verify:wbs": "python tools/validate_quant_engine_wbs_v1.py",
|
||||||
|
"validate:normalized-learning-store": "python tools/validate_normalized_learning_store_v1.py",
|
||||||
|
"validate:dotnet-cutover": "python tools/validate_dotnet_postgresql_json_cutover_v1.py",
|
||||||
|
"validate:runtime-settings": "python tools/validate_runtime_connection_settings_immutability_v1.py",
|
||||||
|
"validate:market-schema": "python tools/validate_market_time_series_schema_v1.py",
|
||||||
|
"test:e2e": "playwright test --project=chromium",
|
||||||
|
"test:evidence": "playwright test --project=evidence"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "1.2.0",
|
"cheerio": "1.2.0",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { defineConfig, devices } from '@playwright/test';
|
|||||||
*/
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './tests/e2e',
|
testDir: './tests/e2e',
|
||||||
|
testIgnore: '**/archive/**',
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
@@ -14,7 +15,7 @@ export default defineConfig({
|
|||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'list',
|
reporter: [['list'], ['json', { outputFile: 'Temp/evidence/playwright-last-run.json' }]],
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
@@ -29,8 +30,14 @@ export default defineConfig({
|
|||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
name: 'chromium',
|
name: 'chromium',
|
||||||
|
testIgnore: ['**/archive/**', '**/evidence/**'],
|
||||||
use: { ...devices['Desktop Chrome'] },
|
use: { ...devices['Desktop Chrome'] },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'evidence',
|
||||||
|
testDir: './tests/e2e/evidence',
|
||||||
|
use: { ...devices['Desktop Chrome'], screenshot: 'on', trace: 'on' },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
"""Auto-generated package."""
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ABSOLUTE_RISK_STOP_V1",
|
|
||||||
"title": "ABSOLUTE_RISK_STOP_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ABSOLUTE_RISK_STOP_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"holdings",
|
|
||||||
"df_map"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ALGORITHM_GUIDANCE_PROOF_V1",
|
|
||||||
"title": "ALGORITHM_GUIDANCE_PROOF_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ALGORITHM_GUIDANCE_PROOF_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ALPHA_EVALUATION_WINDOW_V1",
|
|
||||||
"title": "ALPHA_EVALUATION_WINDOW_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ALPHA_EVALUATION_WINDOW_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"entry_date",
|
|
||||||
"position_class",
|
|
||||||
"t20_return_pct",
|
|
||||||
"t60_return_pct",
|
|
||||||
"benchmark_core_return_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ALPHA_FEEDBACK_LOOP_V1",
|
|
||||||
"title": "ALPHA_FEEDBACK_LOOP_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ALPHA_FEEDBACK_LOOP_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"alpha_evaluation_window_json",
|
|
||||||
"saqg_v1",
|
|
||||||
"brt_verdict",
|
|
||||||
"market_regime"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": [
|
|
||||||
{
|
|
||||||
"field": "alpha_feedback_json",
|
|
||||||
"subfields": [
|
|
||||||
"eligible_t20_fail_rate",
|
|
||||||
"eligible_t60_fail_rate",
|
|
||||||
"recommended_filter_adjustments",
|
|
||||||
"cases_analyzed"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ANTI_CHASE_V1",
|
|
||||||
"title": "ANTI_CHASE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ANTI_CHASE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ANTI_CHASING_VELOCITY_V1",
|
|
||||||
"title": "ANTI_CHASING_VELOCITY_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ANTI_CHASING_VELOCITY_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close",
|
|
||||||
"close_1d_ago",
|
|
||||||
"close_5d_ago",
|
|
||||||
"market_regime"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ANTI_LATE_ENTRY_GATE_V2",
|
|
||||||
"title": "ANTI_LATE_ENTRY_GATE_V2",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ANTI_LATE_ENTRY_GATE_V2"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ANTI_WHIPSAW_GATE_V1",
|
|
||||||
"title": "ANTI_WHIPSAW_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ANTI_WHIPSAW_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close_price",
|
|
||||||
"ma20",
|
|
||||||
"rsi14"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ARTIFACT_FRESHNESS_GATE_V1",
|
|
||||||
"title": "ARTIFACT_FRESHNESS_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ARTIFACT_FRESHNESS_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/AUDIT_REPLAY_SNAPSHOT_V1",
|
|
||||||
"title": "AUDIT_REPLAY_SNAPSHOT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "AUDIT_REPLAY_SNAPSHOT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/BENCHMARK_RELATIVE_TIMESERIES_V1",
|
|
||||||
"title": "BENCHMARK_RELATIVE_TIMESERIES_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "BENCHMARK_RELATIVE_TIMESERIES_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"price.ret5D",
|
|
||||||
"price.ret20D",
|
|
||||||
"price.ret60D",
|
|
||||||
"price.close",
|
|
||||||
"high52w",
|
|
||||||
"globalKospiRet5D_",
|
|
||||||
"globalKospiRet20D_",
|
|
||||||
"globalKospiRet60D_",
|
|
||||||
"globalKospiDrawdown_"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/BLANK_CELL_AUDIT_V1",
|
|
||||||
"title": "BLANK_CELL_AUDIT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "BLANK_CELL_AUDIT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"operational_report_json"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/BREAKEVEN_RATCHET_V1",
|
|
||||||
"title": "BREAKEVEN_RATCHET_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "BREAKEVEN_RATCHET_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"average_cost",
|
|
||||||
"highest_price_since_entry"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/BREAKOUT_FAILURE_STOP_V1",
|
|
||||||
"title": "BREAKOUT_FAILURE_STOP_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "BREAKOUT_FAILURE_STOP_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"prior_high",
|
|
||||||
"close_price",
|
|
||||||
"days_since_breakout"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/BREAKOUT_QUALITY_GATE_V2",
|
|
||||||
"title": "BREAKOUT_QUALITY_GATE_V2",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "BREAKOUT_QUALITY_GATE_V2"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close",
|
|
||||||
"ma20",
|
|
||||||
"ret_3d",
|
|
||||||
"ret_1d",
|
|
||||||
"disparity",
|
|
||||||
"rsi14",
|
|
||||||
"volume",
|
|
||||||
"avg_volume_5d",
|
|
||||||
"timing_score_exit",
|
|
||||||
"distribution_risk_score",
|
|
||||||
"late_chase_risk_score"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CANONICAL_ARTIFACT_RESOLVER_V1",
|
|
||||||
"title": "CANONICAL_ARTIFACT_RESOLVER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CANONICAL_ARTIFACT_RESOLVER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CANONICAL_METRICS_V1",
|
|
||||||
"title": "CANONICAL_METRICS_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CANONICAL_METRICS_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CAPITAL_STYLE_ALLOCATION_V1",
|
|
||||||
"title": "CAPITAL_STYLE_ALLOCATION_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CAPITAL_STYLE_ALLOCATION_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"smart_money_flow_signal_v2_json",
|
|
||||||
"fundamental_multifactor_v3_json",
|
|
||||||
"macro_event_ticker_impact_v1_json",
|
|
||||||
"liquidity_flow_signal_v1_json"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_CREATION_PURPOSE_LOCK_V1",
|
|
||||||
"title": "CASH_CREATION_PURPOSE_LOCK_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_CREATION_PURPOSE_LOCK_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"composite_verdict",
|
|
||||||
"rs_verdict",
|
|
||||||
"brt_verdict",
|
|
||||||
"excess_drawdown_pctp",
|
|
||||||
"recovery_ratio_20d",
|
|
||||||
"sfg_v1"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_FLOOR_V1",
|
|
||||||
"title": "CASH_FLOOR_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_FLOOR_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"total_asset",
|
|
||||||
"settlement_cash_d2_krw",
|
|
||||||
"market_risk_score"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RAISE_PARETO_EXECUTOR_V2",
|
|
||||||
"title": "CASH_RAISE_PARETO_EXECUTOR_V2",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RAISE_PARETO_EXECUTOR_V2"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RAISE_VALUE_OPTIMIZER_V3",
|
|
||||||
"title": "CASH_RAISE_VALUE_OPTIMIZER_V3",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RAISE_VALUE_OPTIMIZER_V3"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RATIOS_V1",
|
|
||||||
"title": "CASH_RATIOS_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RATIOS_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"settlement_cash",
|
|
||||||
"reserved_order_amount",
|
|
||||||
"planned_buy_amount",
|
|
||||||
"sell_cash_proceeds_d2",
|
|
||||||
"total_asset"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": {
|
|
||||||
"settlement_cash_ratio": "settlement_cash / total_asset * 100",
|
|
||||||
"total_cash_ratio": "settlement_cash / total_asset * 100",
|
|
||||||
"buy_power_cash": "settlement_cash - reserved_order_amount",
|
|
||||||
"buy_power_ratio": "(settlement_cash - reserved_order_amount) / total_asset * 100",
|
|
||||||
"post_trade_total_cash_ratio": "(settlement_cash - planned_buy_amount + sell_cash_proceeds_d2) / total_asset * 100"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RECOVERY_OPTIMIZER_V1",
|
|
||||||
"title": "CASH_RECOVERY_OPTIMIZER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RECOVERY_OPTIMIZER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"cash_shortfall_target_krw",
|
|
||||||
"cash_shortfall_min_krw",
|
|
||||||
"sell_candidates_json",
|
|
||||||
"immediate_sell_qty",
|
|
||||||
"sell_limit_price",
|
|
||||||
"holding_qty"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RECOVERY_OPTIMIZER_V4",
|
|
||||||
"title": "CASH_RECOVERY_OPTIMIZER_V4",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RECOVERY_OPTIMIZER_V4"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASH_RECOVERY_V1",
|
|
||||||
"title": "CASH_RECOVERY_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASH_RECOVERY_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASHFLOW_QUALITY_SIGNAL_V1",
|
|
||||||
"title": "CASHFLOW_QUALITY_SIGNAL_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASHFLOW_QUALITY_SIGNAL_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CASHFLOW_STABILITY_GATE_V1",
|
|
||||||
"title": "CASHFLOW_STABILITY_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CASHFLOW_STABILITY_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"operating_cf_krw",
|
|
||||||
"free_cf_krw",
|
|
||||||
"accrual_ratio_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CLA_REGIME_EXIT_CONDITION_V1",
|
|
||||||
"title": "CLA_REGIME_EXIT_CONDITION_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CLA_REGIME_EXIT_CONDITION_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"ticker",
|
|
||||||
"rs_verdict",
|
|
||||||
"brt_verdict",
|
|
||||||
"frg_5d_sh",
|
|
||||||
"volume",
|
|
||||||
"avg_volume_5d",
|
|
||||||
"market_regime"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": [
|
|
||||||
{
|
|
||||||
"field": "cla_exit_status",
|
|
||||||
"unit": "enum [CLA_ACTIVE,CLA_EXIT_WARNING,CLA_EXIT_CONFIRMED]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "cla_exit_signals_triggered",
|
|
||||||
"unit": "list"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "cla_exit_total_weight",
|
|
||||||
"unit": "int"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/COMPLETION_GAP_V1",
|
|
||||||
"title": "COMPLETION_GAP_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "COMPLETION_GAP_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/COMPOSITE_VERDICT_V1",
|
|
||||||
"title": "COMPOSITE_VERDICT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "COMPOSITE_VERDICT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"ss001_grade",
|
|
||||||
"rs_verdict"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/COMPREHENSIVE_PROPOSAL_V1",
|
|
||||||
"title": "COMPREHENSIVE_PROPOSAL_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "COMPREHENSIVE_PROPOSAL_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CONSECUTIVE_STREAK_V1",
|
|
||||||
"title": "CONSECUTIVE_STREAK_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CONSECUTIVE_STREAK_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"daily_close_changes"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CONTINUOUS_EVALUATION_DASHBOARD_V1",
|
|
||||||
"title": "CONTINUOUS_EVALUATION_DASHBOARD_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CONTINUOUS_EVALUATION_DASHBOARD_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/CROSS_SECTION_CONSISTENCY_V1",
|
|
||||||
"title": "CROSS_SECTION_CONSISTENCY_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "CROSS_SECTION_CONSISTENCY_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_INTEGRITY_100_LOCK_V1",
|
|
||||||
"title": "DATA_INTEGRITY_100_LOCK_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_INTEGRITY_100_LOCK_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_INTEGRITY_100_LOCK_V2",
|
|
||||||
"title": "DATA_INTEGRITY_100_LOCK_V2",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_INTEGRITY_100_LOCK_V2"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_INTEGRITY_SCORE_V1",
|
|
||||||
"title": "DATA_INTEGRITY_SCORE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_INTEGRITY_SCORE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_MATURITY_TRUTH_GATE_V1",
|
|
||||||
"title": "DATA_MATURITY_TRUTH_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_MATURITY_TRUTH_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_MATURITY_TRUTH_GATE_VALIDATOR_V1",
|
|
||||||
"title": "DATA_MATURITY_TRUTH_GATE_VALIDATOR_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_MATURITY_TRUTH_GATE_VALIDATOR_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_QUALITY_GATE_V2_PY",
|
|
||||||
"title": "DATA_QUALITY_GATE_V2_PY",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_QUALITY_GATE_V2_PY"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DATA_QUALITY_GATE_V3",
|
|
||||||
"title": "DATA_QUALITY_GATE_V3",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DATA_QUALITY_GATE_V3"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DETERMINISTIC_ROUTING_ENGINE_V1",
|
|
||||||
"title": "DETERMINISTIC_ROUTING_ENGINE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DETERMINISTIC_ROUTING_ENGINE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"harness_context"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DISTRIBUTION_SELL_DETECTOR_V1",
|
|
||||||
"title": "DISTRIBUTION_SELL_DETECTOR_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DISTRIBUTION_SELL_DETECTOR_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close",
|
|
||||||
"high52w",
|
|
||||||
"avg_volume_5d",
|
|
||||||
"volume",
|
|
||||||
"ret5d",
|
|
||||||
"flow_credit",
|
|
||||||
"frg_5d_sh",
|
|
||||||
"inst_5d_sh",
|
|
||||||
"rsi14",
|
|
||||||
"obv_slope_20d"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DIVERGENCE_SCORE_V1",
|
|
||||||
"title": "DIVERGENCE_SCORE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DIVERGENCE_SCORE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close_price",
|
|
||||||
"ma20",
|
|
||||||
"frg_5d_sh",
|
|
||||||
"inst_5d_sh",
|
|
||||||
"flow_credit",
|
|
||||||
"frg_20d_sh"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DRAWDOWN_GUARD_V1",
|
|
||||||
"title": "DRAWDOWN_GUARD_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DRAWDOWN_GUARD_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"win_loss_streak_state",
|
|
||||||
"win_loss_streak_buy_scale"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/DYNAMIC_HEAT_GATE_V1",
|
|
||||||
"title": "DYNAMIC_HEAT_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "DYNAMIC_HEAT_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"market_regime",
|
|
||||||
"total_heat_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EARNINGS_GROWTH_QUALITY_GATE_V1",
|
|
||||||
"title": "EARNINGS_GROWTH_QUALITY_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EARNINGS_GROWTH_QUALITY_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"eps_growth_qoq_pct",
|
|
||||||
"eps_growth_yoy_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EARNINGS_QUALITY_SIGNAL_V1",
|
|
||||||
"title": "EARNINGS_QUALITY_SIGNAL_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EARNINGS_QUALITY_SIGNAL_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ECP_RISK_SCALE_V1",
|
|
||||||
"title": "ECP_RISK_SCALE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ECP_RISK_SCALE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"total_asset",
|
|
||||||
"total_asset_ma10"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EJCE_DIVERGENCE_AUDIT_V1",
|
|
||||||
"title": "EJCE_DIVERGENCE_AUDIT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EJCE_DIVERGENCE_AUDIT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EJCE_VIEW_RENDERER_V1",
|
|
||||||
"title": "EJCE_VIEW_RENDERER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EJCE_VIEW_RENDERER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"ejce_json",
|
|
||||||
"alpha_lead_json",
|
|
||||||
"breakout_quality_gate_json",
|
|
||||||
"anti_chasing_velocity_json",
|
|
||||||
"heat_concentration_json",
|
|
||||||
"portfolio_alpha_confidence"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/ENTRY_TIMING_DECILE_FACTOR_V1",
|
|
||||||
"title": "ENTRY_TIMING_DECILE_FACTOR_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "ENTRY_TIMING_DECILE_FACTOR_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"buy_timing_score",
|
|
||||||
"t5_ledger",
|
|
||||||
"cut_decile"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EXECUTION_CAPACITY_LADDER_V1",
|
|
||||||
"title": "EXECUTION_CAPACITY_LADDER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EXECUTION_CAPACITY_LADDER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"planned_order_amount_krw",
|
|
||||||
"avg_trade_value_20d_krw",
|
|
||||||
"intraday_trade_value_krw",
|
|
||||||
"orderbook_top3_depth_krw",
|
|
||||||
"spread_bps"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EXECUTION_METHOD_LADDER_V1",
|
|
||||||
"title": "EXECUTION_METHOD_LADDER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EXECUTION_METHOD_LADDER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"sell_timing_verdict",
|
|
||||||
"sell_waterfall_gate",
|
|
||||||
"smart_cash_recovery_gate"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EXECUTION_PLAN_COMPILER_V1",
|
|
||||||
"title": "EXECUTION_PLAN_COMPILER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EXECUTION_PLAN_COMPILER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"order_capacity_krw",
|
|
||||||
"revalidation_snapshot",
|
|
||||||
"baseline_snapshot"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EXECUTION_QUALITY_SCORE_V1",
|
|
||||||
"title": "EXECUTION_QUALITY_SCORE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EXECUTION_QUALITY_SCORE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/EXPECTED_EDGE_V1",
|
|
||||||
"title": "EXPECTED_EDGE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "EXPECTED_EDGE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"target_price",
|
|
||||||
"entry_price",
|
|
||||||
"stop_price",
|
|
||||||
"bayesian_confidence_multiplier",
|
|
||||||
"execution_cost_rate"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FIFTY_TWO_WEEK_HIGH_TRIGGER_V1",
|
|
||||||
"title": "FIFTY_TWO_WEEK_HIGH_TRIGGER_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FIFTY_TWO_WEEK_HIGH_TRIGGER_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close_price",
|
|
||||||
"high52w"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FINAL_JUDGMENT_GATE_V1",
|
|
||||||
"title": "FINAL_JUDGMENT_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FINAL_JUDGMENT_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FINANCIAL_HEALTH_SCORE_V1",
|
|
||||||
"title": "FINANCIAL_HEALTH_SCORE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FINANCIAL_HEALTH_SCORE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"roe_pct",
|
|
||||||
"operating_margin_pct",
|
|
||||||
"debt_to_equity",
|
|
||||||
"fcf_b",
|
|
||||||
"sector_type"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FLOW_ACCELERATION_V1",
|
|
||||||
"title": "FLOW_ACCELERATION_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FLOW_ACCELERATION_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"frg_5d_sh",
|
|
||||||
"frg_20d_sh",
|
|
||||||
"close_price",
|
|
||||||
"ma20"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FLOW_CREDIT_V1",
|
|
||||||
"title": "FLOW_CREDIT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FLOW_CREDIT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"close_price",
|
|
||||||
"open_price",
|
|
||||||
"previous_close_price",
|
|
||||||
"volume",
|
|
||||||
"avg_volume_5d",
|
|
||||||
"frg_5d_sh",
|
|
||||||
"inst_5d_sh",
|
|
||||||
"flow_ok"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FOLLOW_THROUGH_DAY_CONFIRM_V1",
|
|
||||||
"title": "FOLLOW_THROUGH_DAY_CONFIRM_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FOLLOW_THROUGH_DAY_CONFIRM_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"days_since_breakout",
|
|
||||||
"ret_since_breakout",
|
|
||||||
"vol_today",
|
|
||||||
"vol_breakout_day",
|
|
||||||
"close",
|
|
||||||
"ma20"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FORECAST_SIMULATION_ENGINE_V1",
|
|
||||||
"title": "FORECAST_SIMULATION_ENGINE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FORECAST_SIMULATION_ENGINE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"net_profit_distribution_after_tax_fee_slippage",
|
|
||||||
"sample_count_total",
|
|
||||||
"sample_count_same_regime",
|
|
||||||
"execution_mode"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FUNDAMENTAL_MULTI_FACTOR_SCORE_V2",
|
|
||||||
"title": "FUNDAMENTAL_MULTI_FACTOR_SCORE_V2",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FUNDAMENTAL_MULTI_FACTOR_SCORE_V2"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"roe_pct",
|
|
||||||
"opm_pct",
|
|
||||||
"revenue_growth_pct",
|
|
||||||
"op_income_growth_pct",
|
|
||||||
"market_share_proxy_pct",
|
|
||||||
"operating_cf_krw",
|
|
||||||
"free_cf_krw",
|
|
||||||
"debt_ratio_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FUNDAMENTAL_MULTIFACTOR_V3",
|
|
||||||
"title": "FUNDAMENTAL_MULTIFACTOR_V3",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FUNDAMENTAL_MULTIFACTOR_V3"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FUNDAMENTAL_QUALITY_GATE_V1",
|
|
||||||
"title": "FUNDAMENTAL_QUALITY_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FUNDAMENTAL_QUALITY_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"roe_pct",
|
|
||||||
"op_income_growth_pct",
|
|
||||||
"debt_ratio_pct",
|
|
||||||
"operating_cf_krw",
|
|
||||||
"pe_ttm"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/FUNDAMENTAL_RAW_INGEST_V1",
|
|
||||||
"title": "FUNDAMENTAL_RAW_INGEST_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "FUNDAMENTAL_RAW_INGEST_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/GOLDEN_CROSS_SIGNAL_V1",
|
|
||||||
"title": "GOLDEN_CROSS_SIGNAL_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "GOLDEN_CROSS_SIGNAL_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"ma20",
|
|
||||||
"ma20_prev",
|
|
||||||
"ma60",
|
|
||||||
"ma60_prev"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/GROWTH_RATE_SIGNAL_V1",
|
|
||||||
"title": "GROWTH_RATE_SIGNAL_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "GROWTH_RATE_SIGNAL_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/HARNESS_DATA_FRESHNESS_GATE_V1",
|
|
||||||
"title": "HARNESS_DATA_FRESHNESS_GATE_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "HARNESS_DATA_FRESHNESS_GATE_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"metadata.generated_at",
|
|
||||||
"metadata.market_date",
|
|
||||||
"today_date"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "schema://formula/HEAT_CONCENTRATION_ALERT_V1",
|
|
||||||
"title": "HEAT_CONCENTRATION_ALERT_V1",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"formula_id": {
|
|
||||||
"const": "HEAT_CONCENTRATION_ALERT_V1"
|
|
||||||
},
|
|
||||||
"owner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"formula_id",
|
|
||||||
"owner",
|
|
||||||
"status",
|
|
||||||
"inputs",
|
|
||||||
"outputs"
|
|
||||||
],
|
|
||||||
"x_formula_inputs": [
|
|
||||||
"heat_share_pct"
|
|
||||||
],
|
|
||||||
"x_formula_outputs": []
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user