WLD DeepCoin 단계별 구조 재편 및 설정·문서 통합
로고스/루트 레거시를 제거하고 deepcoin 패키지·scripts 01~05 CLI·docs/reference로 데이터·GT·분석·매칭·운영 단계를 정리했다. config와 .env 기반 설정, trade_anaysis.html 동기화 포함. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
11
scripts/01_download.py
Normal file
11
scripts/01_download.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""01단계: WLD 봉 데이터 다운로드 → data/coins.db"""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.data.downloader import download
|
||||
|
||||
if __name__ == "__main__":
|
||||
download()
|
||||
11
scripts/02_ground_truth.py
Normal file
11
scripts/02_ground_truth.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""02단계: Ground Truth 매수·매도 타점 생성."""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.ground_truth.ground_truth import run_from_db
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_from_db()
|
||||
11
scripts/03_analyze_enrich.py
Normal file
11
scripts/03_analyze_enrich.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""03단계: 3분~일봉 전 기법 enrich (latest CSV)."""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.analysis.general_analysis_enrich_runner import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
11
scripts/03_analyze_trades.py
Normal file
11
scripts/03_analyze_trades.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""03b단계: Ground Truth 타점 MTF 기술적 스냅샷 CSV."""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.analysis.general_analysis_runner import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
11
scripts/04_match_rules.py
Normal file
11
scripts/04_match_rules.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""04단계: GT 근접 규칙 선택 (스텁)."""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.matching.match_rules import run_match_stub
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_match_stub()
|
||||
13
scripts/05_chart_bb.py
Normal file
13
scripts/05_chart_bb.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
"""05: 3분봉 BB 차트 HTML."""
|
||||
import runpy
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.ops import simulation
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.argv = [sys.argv[0]]
|
||||
simulation.main()
|
||||
13
scripts/05_chart_truth.py
Normal file
13
scripts/05_chart_truth.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
"""05: Ground Truth 차트 + JSON."""
|
||||
import runpy
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.ops import simulation
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.argv = [sys.argv[0], "truth"]
|
||||
simulation.main()
|
||||
11
scripts/05_run_monitor.py
Normal file
11
scripts/05_run_monitor.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""05단계: WLD 실시간 모니터 루프."""
|
||||
import runpy
|
||||
from pathlib import Path
|
||||
|
||||
runpy.run_path(str(Path(__file__).resolve().parent / "_bootstrap.py"))
|
||||
|
||||
from deepcoin.ops.monitor_coin import MonitorCoin
|
||||
|
||||
if __name__ == "__main__":
|
||||
MonitorCoin(cooldown_file=None).run_schedule()
|
||||
17
scripts/README.md
Normal file
17
scripts/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# scripts — 단계별 CLI
|
||||
|
||||
프로젝트 루트에서 실행하세요. 각 스크립트는 `_bootstrap.py`로 `.env`와 `config`를 로드합니다.
|
||||
|
||||
```bash
|
||||
python scripts/01_download.py
|
||||
python scripts/02_ground_truth.py
|
||||
python scripts/03_analyze_enrich.py
|
||||
python scripts/03_analyze_trades.py
|
||||
python scripts/04_match_rules.py # 스텁
|
||||
python scripts/05_chart_truth.py
|
||||
python scripts/05_chart_bb.py
|
||||
python scripts/05_run_monitor.py
|
||||
python scripts/verify_env.py
|
||||
```
|
||||
|
||||
상세 구조: [docs/reference/STRUCTURE.md](../docs/reference/STRUCTURE.md)
|
||||
11
scripts/_bootstrap.py
Normal file
11
scripts/_bootstrap.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
# .env → config 일관 로드
|
||||
from deepcoin.env_loader import load_project_env # noqa: E402
|
||||
|
||||
load_project_env()
|
||||
219
scripts/verify_env.py
Normal file
219
scripts/verify_env.py
Normal file
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
"""`.env` 완전성 및 config 로드 점검."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
ENV_FILE = ROOT / ".env"
|
||||
CONFIG_FILE = ROOT / "config.py"
|
||||
|
||||
# config.py에서 읽는 환경 변수 키 (코드 기본값이 있는 항목)
|
||||
CONFIG_ENV_KEYS = {
|
||||
"BITHUMB_API_URL",
|
||||
"BITHUMB_API_CANDLE_COUNT",
|
||||
"BITHUMB_MINUTE_INTERVALS",
|
||||
"HTS_API_RETRY_SLEEP_SEC",
|
||||
"SYMBOL",
|
||||
"COIN_NAME",
|
||||
"DAILY_INTERVAL_MIN",
|
||||
"ENTRY_INTERVAL",
|
||||
"TREND_INTERVAL_1H",
|
||||
"TREND_INTERVAL_1D",
|
||||
"ALL_INTERVALS",
|
||||
"DOWNLOAD_INTERVALS",
|
||||
"GENERAL_ANALYSIS_INTERVALS",
|
||||
"TIMING_INTERVALS",
|
||||
"TREND_INTERVALS",
|
||||
"INTERVAL_PREFIX",
|
||||
"BB_PERIOD",
|
||||
"BB_STD",
|
||||
"BB_MIN_WIDTH_PCT",
|
||||
"RSI_PERIOD",
|
||||
"DISPARITY_PERIODS",
|
||||
"DISPARITY_OVERBOUGHT",
|
||||
"DISPARITY_OVERSOLD",
|
||||
"MACD_FAST",
|
||||
"MACD_SLOW",
|
||||
"MACD_SIGNAL",
|
||||
"STOCH_K_PERIOD",
|
||||
"STOCH_D_PERIOD",
|
||||
"STOCH_SMOOTH_K",
|
||||
"STOCH_OVERSOLD",
|
||||
"STOCH_OVERBOUGHT",
|
||||
"TREND_RANGE_MA_GAP_PCT",
|
||||
"ALIGN_RSI_OVERSOLD",
|
||||
"ALIGN_RSI_OVERBOUGHT",
|
||||
"ALIGN_RSI_CONFLICT_TIMING_LOW",
|
||||
"ALIGN_RSI_CONFLICT_TIMING_HIGH",
|
||||
"ALIGN_RSI_CONFLICT_TREND_LOW",
|
||||
"ALIGN_RSI_CONFLICT_TREND_HIGH",
|
||||
"ALIGN_BB_POS_LOW",
|
||||
"ALIGN_BB_POS_HIGH",
|
||||
"DOWNLOAD_MONTHS",
|
||||
"DOWNLOAD_MONTHS_1M",
|
||||
"INCREMENTAL_OVERLAP_BARS",
|
||||
"DOWNLOAD_BACKFILL_EXTRA_BARS",
|
||||
"DOWNLOAD_MIN_INCREMENTAL_BARS",
|
||||
"DOWNLOAD_DAILY_EXTRA_DAYS",
|
||||
"CHART_LOOKBACK_DAYS",
|
||||
"DB_READ_LIMIT_DEFAULT",
|
||||
"DB_ROW_WARMUP_BARS",
|
||||
"DB_ROW_MIN_DAILY_BARS",
|
||||
"DB_ROW_DAILY_PADDING_DAYS",
|
||||
"DB_PATH",
|
||||
"GROUND_TRUTH_FILE",
|
||||
"GT_UNLIMITED_CHRONOLOGICAL_DAYS",
|
||||
"GT_MIN_SWING_PCT",
|
||||
"GT_PIVOT_ORDER",
|
||||
"GT_MIN_BARS_BETWEEN",
|
||||
"GT_MAX_ROUND_TRIPS",
|
||||
"GT_SELECTION_MODE",
|
||||
"GT_MIN_LEG_PCT",
|
||||
"GT_BUY_MIN_SWING_PCT",
|
||||
"GT_BUY_BB_MAX",
|
||||
"GT_BUY_MIN_BARS",
|
||||
"GT_MAX_BUYS_PER_LEG",
|
||||
"GT_MAX_SELLS_PER_LEG",
|
||||
"GT_SELL_SPLIT_GAP_PCT",
|
||||
"GT_MARKER_SIZE_MIN",
|
||||
"GT_MARKER_SIZE_MAX",
|
||||
"GT_INITIAL_CASH_KRW",
|
||||
"TRADING_FEE_RATE",
|
||||
"MONITOR_LOOP_SLEEP_SEC",
|
||||
"MONITOR_POOL_WORKERS",
|
||||
"MONITOR_DEFAULT_INTERVAL",
|
||||
"MONITOR_API_RETRIES",
|
||||
"MONITOR_API_BONG_COUNT",
|
||||
"MONITOR_SLEEP_AFTER_REQUEST_SEC",
|
||||
"MONITOR_SLEEP_RATE_LIMIT_SEC",
|
||||
"MONITOR_SLEEP_BETWEEN_CHUNKS_SEC",
|
||||
"MONITOR_API_CHUNK_BARS",
|
||||
"MONITOR_MA_WINDOWS",
|
||||
"MONITOR_NORM_WINDOW",
|
||||
"MONITOR_TELEGRAM_BATCH_SIZE",
|
||||
"GA_COL_PREFIX",
|
||||
"LOOKBACK_BARS",
|
||||
"CONTEXT_TAIL_ROWS",
|
||||
"GA_DEFAULT_TAIL_EXPORT",
|
||||
"GA_PATTERN_TOLERANCE_PCT",
|
||||
"GA_VP_BINS",
|
||||
"GA_VP_VALUE_AREA_PCT",
|
||||
"GA_HV_ROLLING_BARS",
|
||||
"GA_HV_PERCENTILE_WINDOW",
|
||||
"GA_HV_ANNUALIZE_SQRT",
|
||||
"GA_DIVERGENCE_LOOKBACK",
|
||||
"GA_SMA_PERIODS",
|
||||
"GA_EMA_SPANS",
|
||||
"GA_ATR_PERIOD",
|
||||
"GA_KELTNER_ATR_MULT",
|
||||
"GA_AO_FAST",
|
||||
"GA_AO_SLOW",
|
||||
"GA_LINREG_WINDOW",
|
||||
"GA_ADX_PERIOD",
|
||||
"GA_ADX_TREND_THRESHOLD",
|
||||
"GA_SUPERTREND_ATR_MULT",
|
||||
"GA_VOL_SPIKE_MULT",
|
||||
"GA_VOL_MA_WINDOW",
|
||||
"GA_CCI_PERIOD",
|
||||
"GA_WILLIAMS_PERIOD",
|
||||
"GA_ROC_PERIOD",
|
||||
"GA_MFI_PERIOD",
|
||||
"GA_CMF_PERIOD",
|
||||
"GA_DONCHIAN_PERIOD",
|
||||
"GA_BB_SQUEEZE_WINDOW",
|
||||
"GA_BB_SQUEEZE_QUANTILE",
|
||||
"GA_PIVOT_ORDER",
|
||||
"GA_PSAR_AF_START",
|
||||
"GA_PSAR_AF_STEP",
|
||||
"GA_PSAR_AF_MAX",
|
||||
}
|
||||
|
||||
# 비어 있어도 되는 선택 항목 (현재는 모두 채움)
|
||||
OPTIONAL_EMPTY = frozenset()
|
||||
|
||||
|
||||
def parse_env_file(path: Path) -> dict[str, str]:
|
||||
"""`.env` 키=값 파싱."""
|
||||
out: dict[str, str] = {}
|
||||
if not path.is_file():
|
||||
return out
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, _, val = line.partition("=")
|
||||
out[key.strip()] = val.strip()
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
errors: list[str] = []
|
||||
|
||||
if not ENV_FILE.is_file():
|
||||
errors.append(f".env 없음: {ENV_FILE}")
|
||||
for e in errors:
|
||||
print(f"FAIL: {e}")
|
||||
return 1
|
||||
|
||||
env_vars = parse_env_file(ENV_FILE)
|
||||
empty = [k for k, v in env_vars.items() if v == "" and k not in OPTIONAL_EMPTY]
|
||||
missing = sorted(CONFIG_ENV_KEYS - set(env_vars.keys()))
|
||||
extra = sorted(set(env_vars.keys()) - CONFIG_ENV_KEYS - {
|
||||
"BITHUMB_ACCESS_KEY",
|
||||
"BITHUMB_SECRET_KEY",
|
||||
"COIN_TELEGRAM_BOT_TOKEN",
|
||||
"COIN_TELEGRAM_CHAT_ID",
|
||||
})
|
||||
|
||||
if empty:
|
||||
errors.append(f"빈 값: {', '.join(empty)}")
|
||||
if missing:
|
||||
errors.append(f"config 대비 .env 누락: {', '.join(missing)}")
|
||||
if extra:
|
||||
print(f"WARN: config 미사용 .env 키: {', '.join(extra)}")
|
||||
|
||||
from deepcoin.env_loader import env_status, load_project_env
|
||||
|
||||
loaded = load_project_env(override=True)
|
||||
if not loaded:
|
||||
errors.append("load_project_env: .env 로드 실패 (python-dotenv 확인)")
|
||||
|
||||
import config # noqa: E402
|
||||
|
||||
checks = [
|
||||
("SYMBOL", config.SYMBOL, env_vars.get("SYMBOL")),
|
||||
("DB_PATH", config.DB_PATH, env_vars.get("DB_PATH")),
|
||||
("BITHUMB_ACCESS_KEY", bool(config.BITHUMB_ACCESS_KEY), bool(env_vars.get("BITHUMB_ACCESS_KEY"))),
|
||||
("LOOKBACK_BARS[3]", config.LOOKBACK_BARS.get(3), 120),
|
||||
]
|
||||
for name, got, expected in checks:
|
||||
if got != expected and expected is not None:
|
||||
errors.append(f"config 불일치 {name}: got={got!r} expected={expected!r}")
|
||||
|
||||
status = env_status()
|
||||
print("env_status:", status)
|
||||
print(f".env 키 수: {len(env_vars)} (config 필수 {len(CONFIG_ENV_KEYS)})")
|
||||
print(f"SYMBOL={config.SYMBOL} DB_PATH={config.DB_PATH}")
|
||||
print(f"BITHUMB_KEY set={bool(config.BITHUMB_ACCESS_KEY)} TELEGRAM set={bool(config.COIN_TELEGRAM_BOT_TOKEN)}")
|
||||
|
||||
if errors:
|
||||
print("\n=== 점검 실패 ===")
|
||||
for e in errors:
|
||||
print(f" - {e}")
|
||||
return 1
|
||||
|
||||
print("\n=== 점검 통과: .env → config 로드 정상 ===")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user