{"id":49280303,"url":"https://github.com/2sem/coinone-autotrader","last_synced_at":"2026-04-25T18:06:55.765Z","repository":{"id":349144368,"uuid":"1201158261","full_name":"2sem/coinone-autotrader","owner":"2sem","description":"Safe dry-run scaffold for Coinone autotrading experiments.","archived":false,"fork":false,"pushed_at":"2026-04-11T13:16:33.000Z","size":217,"stargazers_count":0,"open_issues_count":18,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T14:10:51.062Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2sem.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-04T09:34:59.000Z","updated_at":"2026-04-11T13:16:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/2sem/coinone-autotrader","commit_stats":null,"previous_names":["2sem/coinone-autotrader"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/2sem/coinone-autotrader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sem%2Fcoinone-autotrader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sem%2Fcoinone-autotrader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sem%2Fcoinone-autotrader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sem%2Fcoinone-autotrader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2sem","download_url":"https://codeload.github.com/2sem/coinone-autotrader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sem%2Fcoinone-autotrader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32271291,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T09:15:33.318Z","status":"ssl_error","status_checked_at":"2026-04-25T09:15:31.997Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-25T18:06:55.160Z","updated_at":"2026-04-25T18:06:55.755Z","avatar_url":"https://github.com/2sem.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# coinone-autotrader\n\nPhase 5 adds an execution-preview layer alongside the existing dry-run trading scaffold. It keeps live trading disabled, preserves the current `trade:once`, `agent:decision`, and reporting flows, and now turns real `trade:once` decisions plus live or mock Coinone data into persisted would-submit order previews with final validation results while never sending a live order. It also adds manual approval plus mock submit scaffolding so operators can approve a specific `previewId`, attempt a guarded submit, and persist approval/submit audit artifacts without calling the live order API.\n\nThe main executable workflow remains the dry-run `trade:once` command for the current deterministic strategy engine. In parallel, `agent:decision` now builds a normalized Coinone market/account snapshot from the existing CLI-backed data layer, validates a richer buy/sell/hold decision payload, persists snapshot/decision/execution/state files under `artifacts/agent-decision`, and supports either the existing deterministic mock provider or an OpenAI-compatible model endpoint through built-in `fetch`. Reporting commands continue to reuse the dry-run snapshot, build markdown issue drafts with a vertical Mermaid workflow diagram, optionally create GitHub issues through the REST API, and notify Slack through an incoming webhook. Phase 4 keeps internal reasoning, risk, and provider metadata in English while exposing Korean user-facing summaries for CLI/reporting/Slack; report titles stay stable for exact-title dedupe.\n\n## Safety defaults\n\n- Dry run is enabled by default with `DRY_RUN=true`.\n- `.env` files are ignored by git so secrets stay local.\n- Live order placement is still not implemented.\n- `agent:decision` persists inspectable JSON artifacts only; it never places orders.\n- Dry-run execution artifacts record what would have been sent for execution, but they are always blocked from live submission.\n- `execution:preview` builds would-submit order payloads and final validation results, then persists them without calling any order API.\n- `execution:approve` binds a short-lived manual approval to exactly one `previewId` and persists it for audit.\n- `execution:submit` fails closed unless preview, approval, and final safety gates all pass; `SUBMIT_ADAPTER=mock` stays the default.\n- Coinone 계좌 정보는 판단에 항상 포함되며, 읽지 못하면 보수적으로 `hold` 처리합니다.\n- Missing or uncertain account data now resolves to `hold` instead of guessing.\n- Daily risk caps are enforced only from completed orders and default to `hold` when account history is unavailable.\n- `USDC` and `USDT` automatically use the `stablecoin` profile unless `STRATEGY_PROFILE_OVERRIDES` says otherwise.\n- GitHub issue creation uses built-in `fetch`; no extra HTTP client is added.\n\n## Requirements\n\n- Node.js 20+\n- npm\n\n## Setup\n\n```bash\ncp .env.example .env\nnpm install\nnpm run coinone:install\nnpm run coinone:doctor\n```\n\n`npm run coinone:install` clones `2sem/coinone-api-cli` into `.vendor/coinone-api-cli`, checks out pinned commit `d65495cfdb9e1ca1ae6dc5e401497e27f240c958` (latest upstream `main` including the fee-response improvements used by the runtime workflow), installs its dependencies, and builds the local CLI entrypoint used by this project.\n\nThis explicit installation contract is used instead of an npm/git package dependency because the upstream repository currently does not publish build artifacts in a directly consumable package form.\n\n`npm run coinone:doctor` runs the pinned vendored CLI health check locally, loads values from the repo `.env`, and confirms whether private auth env vars are configured without placing orders.\n\n## Run once\n\n```bash\nnpm run trade:once\nnpm run agent:decision\nnpm run execution:preview\nnpm run execution:approve\nnpm run execution:submit\n```\n\nDry-run behavior:\n\n- `MARKET_DATA_MODE=auto`: try the local `coinone` CLI first, then fall back to mock data.\n- `MARKET_DATA_MODE=live`: require the local CLI and fail if it cannot return data.\n- `MARKET_DATA_MODE=mock`: skip all external API reads and use deterministic local fixtures.\n- Coinone credentials가 설정되어 있으면 balances와 최근 30일 completed orders를 항상 함께 읽어 판단에 반영합니다.\n- Decision output stays conservative: cooldown blocks repeat trades, completed orders enforce `MAX_DAILY_BUY_KRW` and `MAX_TRADES_PER_DAY`, stablecoins accumulate with smaller capped buys and no sell signal, missing balance or pricing data yields `hold`, and live order placement stays disabled.\n\n## Execution Preview\n\n```bash\nMARKET_DATA_MODE=auto npm run execution:preview\nMARKET_DATA_MODE=live npm run execution:preview\n```\n\nBehavior:\n\n- Reuses the existing `trade:once` market snapshot and deterministic decision engine instead of inventing a separate strategy path.\n- Converts each non-hold decision into a realistic would-submit limit-order payload with `side`, `type`, `price`, `quantity`, `value`, and `pair`.\n- Runs final validation gates for payload completeness, allowlist membership, `MAX_ORDER_KRW`, `MIN_CASH_RESERVE_KRW`, `ENABLE_LIVE_TRADING`, `TRADING_KILL_SWITCH`, and `DRY_RUN` policy.\n- Persists `previews/latest.json` plus dated copies under `EXECUTION_PREVIEW_OUTPUT_DIR`.\n- Routine preview Slack delivery is silent by default; set `SLACK_NOTIFY_ROUTINE_PREVIEW=true` only if you want every preview run to page Slack.\n- Keeps Korean CLI summaries for operators while validation gate details remain English for debugging.\n- Never sends a live order, even if `ENABLE_LIVE_TRADING=true` and `DRY_RUN=false` are set locally.\n\n## Approval And Submit Scaffold\n\n```bash\nMARKET_DATA_MODE=mock npm run execution:preview\nMARKET_DATA_MODE=mock npm run execution:approve\nMARKET_DATA_MODE=mock npm run execution:submit\n\nMARKET_DATA_MODE=mock npm run execution:approve -- --preview-id=execution-preview-2026-04-04T00-00-00-000Z\nMARKET_DATA_MODE=mock npm run execution:submit -- --preview-id=execution-preview-2026-04-04T00-00-00-000Z --approval-id=execution-approval-2026-04-04T00-01-00-000Z\n```\n\nBehavior:\n\n- `execution:approve` loads the latest preview by default, or a specific preview via `--preview-id=...`.\n- Approval artifacts are written to `approvals/latest.json` plus dated copies under `EXECUTION_PREVIEW_OUTPUT_DIR`.\n- Each approval expires after `EXECUTION_APPROVAL_WINDOW_SECONDS` and is bound to exactly one `previewId`.\n- `execution:submit` validates preview schema, approval presence, preview/approval ID match, approval expiry, and whether the preview contains at least one submittable entry.\n- Submit attempts fail closed when approval is missing, expired, or linked to another preview.\n- Submit artifacts are written to `submits/latest.json` plus dated copies even when the submit is blocked.\n- `SUBMIT_ADAPTER=mock` records mock order IDs and never places a real Coinone order.\n- `SUBMIT_ADAPTER=coinone-live` can submit a real Coinone limit order, but only when `ENABLE_LIVE_TRADING=true`, `DRY_RUN=false`, and `TRADING_KILL_SWITCH=false` all hold.\n- For the first live test, keep `SELECTION_MODE=allowlist`, `TRADE_TARGETS=USDC`, and a very small `MAX_ORDER_KRW`.\n\n## Agent Decision Dry Run\n\n```bash\nMARKET_DATA_MODE=mock npm run agent:decision\nMARKET_DATA_MODE=mock npm run report:agent-trade-run\n```\n\nBehavior:\n\n- Reuses the existing Coinone CLI-backed snapshot loader and selection logic.\n- Normalizes the selected market/account view into a versioned snapshot contract.\n- Validates both the snapshot contract and the returned decision contract.\n- Validates the decision again before generating any execution artifact.\n- Persists `snapshots/latest.json`, `decisions/latest.json`, `executions/latest.json`, and `state/latest.json` plus dated copies under `AGENT_DECISION_OUTPUT_DIR`.\n- Uses `AGENT_DECISION_PROVIDER=mock` by default for local runs; `openai-compatible` sends a strict JSON request to `AGENT_PROVIDER_ENDPOINT` with built-in `fetch` only.\n- Keeps the internal prompt and reasoning contract in English, while deriving Korean `userFacing` fields locally for CLI/reporting output.\n- If the OpenAI-compatible provider is selected without `AGENT_PROVIDER_ENDPOINT`, `AGENT_PROVIDER_API_KEY`, or `AGENT_PROVIDER_MODEL`, the run fails closed before any execution artifact is written unless `AGENT_PROVIDER_FALLBACK_TO_MOCK=true` is explicitly set.\n- If the OpenAI-compatible call fails, returns invalid JSON, or fails contract normalization, the run either falls back to the mock provider when `AGENT_PROVIDER_FALLBACK_TO_MOCK=true` or fails safely without placing orders.\n- Returns `buy`/`sell`/`hold` schema support with richer fields such as confidence score, risk notes, state updates, and provider metadata; execution remains dry-run-only even for model-backed decisions.\n- CLI output now prints a short decision/execution summary before the full JSON payload.\n- `report:agent-trade-run` keeps the existing deterministic `report:trade-run` path unchanged and writes a separate workflow bundle under `artifacts/agent-trade-run/` with Korean summary text plus copied `agent-snapshot-latest.json`, `agent-decision-latest.json`, `agent-execution-latest.json`, and `agent-state-latest.json` files.\n\n## Generate reports\n\n```bash\nnpm run report:daily\nnpm run report:monthly\n```\n\nReporting behavior:\n\n- Each run writes a markdown draft into `REPORT_OUTPUT_DIR`.\n- Daily and monthly report bodies and related Slack report notifications are written in Korean by default.\n- If `GITHUB_REPOSITORY` and `GITHUB_CREATE_ISSUES=true` are set, the app creates or updates the issue.\n- Local runs prefer the authenticated `gh` CLI session for issue creation and updates.\n- GitHub Actions can continue using the built-in `github.token` environment when available.\n- If issue creation is skipped or blocked, the command still returns a markdown path and manual GitHub issue URL metadata when a repository is configured.\n- If `SLACK_WEBHOOK_URL` is set, Slack delivery now follows the notification policy: routine preview and routine dry-run events are silent by default, while daily/monthly reports plus action-needed or blocked events stay eligible.\n\n## GitHub Actions workflows\n\nThe repo includes four GitHub Actions workflows under `.github/workflows`:\n\n- `trade-run.yml`: scheduled or manual dry-run execution with artifact upload, Slack alerting, and optional action-needed issue creation.\n- `agent-trade-run.yml`: manual agent-driven dry-run execution with artifact upload, Korean workflow summary, copied agent artifacts, Slack alerting, and optional action-needed issue creation.\n- `daily-report.yml`: scheduled or manual daily report generation using the existing report flow.\n- `monthly-report.yml`: scheduled or manual monthly report generation using the existing report flow.\n\nWorkflow defaults stay safe:\n\n- Node 20 is used in every workflow.\n- `DRY_RUN=true` is forced in CI.\n- `MARKET_DATA_MODE=mock` is the default for both schedules and manual dispatches.\n- Coinone 계좌 정보 조회는 워크플로에서도 항상 포함됩니다.\n- Each workflow has a concurrency guard so overlapping runs on the same ref do not execute in parallel.\n\nSchedule defaults are KST-friendly and documented in UTC for GitHub Actions cron syntax:\n\n- `trade-run.yml`: every day at `09:00` and `18:00` KST (`00:00` and `09:00` UTC).\n- `daily-report.yml`: every day at `09:05` KST (`00:05` UTC).\n- `monthly-report.yml`: first day of the month at `09:10` KST (`00:10` UTC).\n\n### Workflow dispatch inputs\n\n`trade-run.yml`, `daily-report.yml`, and `monthly-report.yml` expose the same safe manual inputs:\n\n| Input | Purpose | Default |\n| --- | --- | --- |\n| `market_data_mode` | `mock`, `auto`, or `live` | `mock` |\n| `selection_mode` | `allowlist` or `auto` | `allowlist` |\n| `trade_targets` | Comma-separated targets for allowlist mode | `BTC,ETH` |\n| `auto_selection_universe` | Comma-separated targets for auto mode | `BTC,ETH,XRP,SOL` |\n| `excluded_targets` | Comma-separated exclusions | empty |\n| `max_selected_assets` | Max assets to keep in auto mode | `5` |\n| `create_github_issue` | Enables report or action-needed GitHub issue creation | `false` |\n\n`agent-trade-run.yml` exposes the same dry-run market-selection inputs plus one additional manual input:\n\n| Input | Purpose | Default |\n| --- | --- | --- |\n| `agent_decision_provider` | `mock` or `openai-compatible` | `mock` |\n\n### GitHub Actions vars and secrets contract\n\nOptional repository variables:\n\n- `COINONE_MARKET_DATA_MODE`\n- `COINONE_SELECTION_MODE`\n- `COINONE_TRADE_TARGETS`\n- `COINONE_AUTO_SELECTION_UNIVERSE`\n- `COINONE_EXCLUDED_TARGETS`\n- `COINONE_MAX_SELECTED_ASSETS`\n- `ENABLE_LIVE_TRADING`\n- `TRADING_KILL_SWITCH`\n- `COINONE_CLI_TIMEOUT_MS`\n- `COINONE_CLI_BASE_URL`\n- `CREATE_GITHUB_ISSUE`\n- `ACTIONS_ISSUE_LABELS`\n- `MAX_OPEN_POSITIONS`\n- `MAX_PORTFOLIO_EXPOSURE_PCT`\n- `AGENT_DECISION_PROVIDER`\n- `AGENT_PROVIDER_ENDPOINT`\n- `AGENT_PROVIDER_MODEL`\n- `AGENT_PROVIDER_PROMPT_VERSION`\n- `AGENT_PROVIDER_TEMPERATURE`\n- `AGENT_PROVIDER_TIMEOUT_MS`\n- `AGENT_PROVIDER_FALLBACK_TO_MOCK`\n\nOptional repository secrets:\n\n- `COINONE_ACCESS_TOKEN`\n- `COINONE_SECRET_KEY`\n- `AGENT_PROVIDER_API_KEY`\n- `SLACK_WEBHOOK_URL`\n\nFor the OpenAI-compatible agent path in GitHub Actions, keep the endpoint/model/prompt settings in repository variables and store only `AGENT_PROVIDER_API_KEY` as a secret. If those values are missing while `agent_decision_provider=openai-compatible`, the run fails closed before execution artifacts are written unless `AGENT_PROVIDER_FALLBACK_TO_MOCK=true` is configured.\n\nThe daily and monthly workflows also pass the built-in GitHub Actions `github.token` to the app as `GITHUB_TOKEN` and use `github.repository` as `GITHUB_REPOSITORY`, so no extra GitHub secret is required for same-repo issue creation. Local runs can rely on `gh auth login` instead.\n\nAll workflows now pass the live-safety gates and portfolio caps into the runtime. Keep `ENABLE_LIVE_TRADING=false` for normal operation, and flip `TRADING_KILL_SWITCH=true` if you want an explicit emergency stop recorded in dry-run/report output.\n\nWhen issue creation is enabled, daily and monthly runs search open issues in the configured repo by the exact report title for that period. If a matching issue is already open, the run updates that issue in place; otherwise it creates a new one. Slack notifications still include the issue link in either case.\n\nThe trade-run workflow now applies the same exact-title open-issue dedupe behavior for action-needed issues: it updates the matching open issue when found and only creates a new issue when no exact title match exists. Slack action-needed notifications are preserved.\n\nEach workflow uploads an `artifacts/\u003cworkflow-name\u003e/` bundle containing raw JSON output, a Markdown summary, and machine-readable status metadata. Runs that fail or need follow-up are surfaced in the workflow summary, can notify Slack when `SLACK_WEBHOOK_URL` is configured, and can open GitHub issues when issue creation is enabled.\n\nThe agent workflow bundle additionally includes copied latest agent snapshot/decision/execution/state JSON files so the uploaded artifact contains both the high-level summary and the inspectable dry-run decision records.\n\n## Build\n\n```bash\nnpm run build\nnpm run coinone:doctor\n```\n\n## Configuration\n\nThe app loads environment variables from `.env` and process environment.\n\n| Variable | Purpose | Default |\n| --- | --- | --- |\n| `DRY_RUN` | Keeps execution in simulation mode | `true` |\n| `ENABLE_LIVE_TRADING` | Future live execution gate; keep `false` until a guarded live adapter exists | `false` |\n| `TRADING_KILL_SWITCH` | Emergency stop for any future live execution path | `false` |\n| `QUOTE_CURRENCY` | Quote currency used for markets | `KRW` |\n| `MARKET_DATA_MODE` | `auto`, `live`, or `mock` market-data source | `auto` |\n| `COINONE_CLI_PATH` | Optional path to `coinone` executable or built JS entrypoint | auto-detect `which coinone`, then `.vendor/...` fallback |\n| `COINONE_CLI_TIMEOUT_MS` | Timeout for each local CLI invocation | `15000` |\n| `COINONE_CLI_BASE_URL` | Optional Coinone-compatible base URL for mocks/proxies | empty |\n| `SELECTION_MODE` | Asset selection strategy: `allowlist` or `auto` | `allowlist` |\n| `RISK_PROFILE` | High-level risk mode: `conservative`, `balanced`, or `aggressive` | `balanced` |\n| `TRADE_TARGETS` | Comma-separated assets used in `allowlist` mode | empty |\n| `AUTO_SELECTION_UNIVERSE` | Comma-separated candidate assets for `auto` mode | empty |\n| `MAX_SELECTED_ASSETS` | Maximum assets selected in `auto` mode | `5` |\n| `EXCLUDED_TARGETS` | Comma-separated assets to always exclude | empty |\n| `DEFAULT_STRATEGY_PROFILE` | Fallback strategy profile for non-overridden assets: `default` or `stablecoin` | `default` |\n| `STABLECOIN_TARGETS` | Assets that automatically use the `stablecoin` profile unless overridden | `USDC,USDT` |\n| `STRATEGY_PROFILE_OVERRIDES` | Comma-separated `TARGET:PROFILE` mappings such as `USDT:default` | empty |\n| `MAX_ORDER_KRW` | Optional override for one recommended buy order value cap | derived from `RISK_PROFILE` |\n| `MAX_POSITION_PER_ASSET_KRW` | Optional override for one asset's KRW exposure cap | derived from `RISK_PROFILE` |\n| `MAX_DAILY_BUY_KRW` | Optional override for total completed buy value cap per UTC day | derived from `RISK_PROFILE` |\n| `MAX_TRADES_PER_DAY` | Optional override for total completed trades per UTC day | derived from `RISK_PROFILE` |\n| `MAX_OPEN_POSITIONS` | Optional override for simultaneously held positions | derived from `RISK_PROFILE` |\n| `MAX_PORTFOLIO_EXPOSURE_PCT` | Optional override for portfolio exposure cap | derived from `RISK_PROFILE` |\n| `MIN_CASH_RESERVE_KRW` | Optional override for KRW cash reserve | derived from `RISK_PROFILE` |\n| `COOLDOWN_MINUTES` | Optional override for per-target cooldown | derived from `RISK_PROFILE` |\n| `BUY_FRACTION_OF_CASH` | Optional override for buy sizing fraction | derived from `RISK_PROFILE` |\n| `SELL_FRACTION_OF_POSITION` | Optional override for sell sizing fraction | derived from `RISK_PROFILE` |\n| `AGENT_DECISION_PROVIDER` | Agent provider implementation used by `agent:decision`: `mock` or `openai-compatible` | `mock` |\n| `AGENT_DECISION_OUTPUT_DIR` | Output directory for normalized snapshot, decision, and state files | `artifacts/agent-decision` |\n| `EXECUTION_PREVIEW_OUTPUT_DIR` | Output directory for persisted execution-preview artifacts | `artifacts/execution-preview` |\n| `EXECUTION_APPROVAL_WINDOW_SECONDS` | Manual approval validity window before `execution:submit` must reject it | `300` |\n| `AGENT_PROVIDER_ENDPOINT` | Full OpenAI-compatible chat completions endpoint used when `AGENT_DECISION_PROVIDER=openai-compatible` | empty |\n| `AGENT_PROVIDER_API_KEY` | Bearer token for the OpenAI-compatible endpoint | empty |\n| `AGENT_PROVIDER_MODEL` | Provider model identifier sent to the OpenAI-compatible endpoint and recorded into decision metadata | empty |\n| `AGENT_PROVIDER_PROMPT_VERSION` | Prompt contract version recorded into provider metadata | `phase-4` |\n| `AGENT_PROVIDER_TEMPERATURE` | Optional provider temperature sent to the endpoint and recorded into decision metadata | empty |\n| `AGENT_PROVIDER_TIMEOUT_MS` | Timeout for the OpenAI-compatible provider request | `20000` |\n| `AGENT_PROVIDER_FALLBACK_TO_MOCK` | If `true`, automatically re-runs `agent:decision` with the deterministic mock provider when the OpenAI-compatible path is misconfigured or fails | `false` |\n| `COINONE_ACCESS_TOKEN` | Coinone private API access token used for account-based 판단과 리포트 | empty |\n| `COINONE_SECRET_KEY` | Coinone private API secret key used for account-based 판단과 리포트 | empty |\n| `SLACK_WEBHOOK_URL` | Incoming webhook for issue-link or action-needed notifications | empty |\n| `SLACK_NOTIFY_ROUTINE_PREVIEW` | Enables Slack for routine execution preview runs | `false` |\n| `SLACK_NOTIFY_ROUTINE_DRY_RUN` | Enables Slack for routine dry-run trade or agent runs | `false` |\n| `SLACK_NOTIFY_APPROVAL_NEEDED` | Keeps approval-needed notifications eligible for Slack | `true` |\n| `SLACK_NOTIFY_ACTION_NEEDED` | Keeps blocked or action-needed notifications eligible for Slack | `true` |\n| `SLACK_NOTIFY_DAILY_REPORT` | Keeps daily report notifications eligible for Slack | `true` |\n| `SLACK_NOTIFY_MONTHLY_REPORT` | Keeps monthly report notifications eligible for Slack | `true` |\n| `SLACK_NOTIFY_LIVE_SUBMIT` | Reserves Slack eligibility for future live submit notifications | `true` |\n| `GITHUB_REPOSITORY` | Repository for issue creation in `owner/repo` form | empty |\n| `GITHUB_TOKEN` | Optional GitHub token for REST API issue creation; local runs can use `gh auth login` instead | empty |\n| `GITHUB_API_BASE_URL` | GitHub REST API base URL | `https://api.github.com` |\n| `GITHUB_CREATE_ISSUES` | Enables live GitHub issue creation for report runs | `false` |\n| `REPORT_OUTPUT_DIR` | Directory where markdown issue drafts are written | `reports/generated` |\n\n## Selection behavior\n\n- `allowlist`: selects `TRADE_TARGETS`, removes `EXCLUDED_TARGETS`, and drops markets missing from the fetched market list.\n- `auto`: prefers `AUTO_SELECTION_UNIVERSE`; if that is empty it ranks targets from fetched ticker quote volume, removes `EXCLUDED_TARGETS`, then limits to `MAX_SELECTED_ASSETS`.\n\n## Decision behavior\n\n- 기본 전략은 **분할 매수 / 분할 매도**입니다. 한 번에 전량 매수/매도하지 않고, 잔고·보유 수량·최근 체결을 함께 보고 보수적으로 나눠서 판단합니다.\n- `RISK_PROFILE=conservative|balanced|aggressive`는 주문금액, 현금 보존, 거래 횟수, 보유 포지션 수 같은 기본 안전 기준을 자동으로 정합니다.\n- 세부 숫자 설정은 모두 optional override입니다. 비워두면 `RISK_PROFILE` 기준값을 사용합니다.\n- `default` profile: keeps the existing conservative behavior, allowing capped buys when flat and capped sells when a held position reaches the take-profit or stop-loss band.\n- `stablecoin` profile: auto-applies to `USDC` and `USDT` unless overridden, halves per-buy sizing, blocks sells, and only accumulates while daily trade and buy caps still have room.\n- `buy`: only when there is no current position, available KRW remains above `MIN_CASH_RESERVE_KRW`, sizing stays within `MAX_ORDER_KRW`, `MAX_POSITION_PER_ASSET_KRW`, `MAX_DAILY_BUY_KRW`, `MAX_TRADES_PER_DAY`, `MAX_OPEN_POSITIONS`, and `MAX_PORTFOLIO_EXPOSURE_PCT`, and the target is outside the cooldown window.\n- `sell`: only when a position exists, the resolved profile allows sells, average entry is available, and the current best bid is at least 3% above or 5% below average entry; the recommended quantity is limited by `SELL_FRACTION_OF_POSITION`.\n- `hold`: default whenever account data is unavailable, prices are incomplete, average entry is missing, cooldown is active, daily caps are exhausted, or no safe budget remains.\n\nDry-run output now includes the resolved profile per target, signal details, daily risk-cap usage, portfolio-cap usage, future live-execution block reasons, hold explanations, a small account preview, a portfolio snapshot, and per-target decisions whenever Coinone credentials are present.\n\n## Project layout\n\n```text\nsrc/\n  agent/          Agent snapshot, contract validation, provider, dry-run execution, and state persistence\n  adapters/       Local CLI wrapper for coinone --json\n  cli/            Command entrypoints\n  config/         Env parsing and app config\n  reporting/      Slack delivery, issue drafting, and report orchestration\n  trading/        Selection, market snapshot loading, and dry-run workflow\nscripts/\n  install-coinone-cli.mjs\n```\n\n## Local verification\n\n```bash\ncp .env.example .env\nnpm install\nnpm run coinone:install\nnpm run coinone:doctor\nnpm run build\nRISK_PROFILE=balanced npm run trade:once\nMARKET_DATA_MODE=mock npm run agent:decision\nMARKET_DATA_MODE=mock npm run report:agent-trade-run\nMARKET_DATA_MODE=mock AGENT_DECISION_PROVIDER=openai-compatible AGENT_PROVIDER_ENDPOINT=http://127.0.0.1:4010/v1/chat/completions AGENT_PROVIDER_API_KEY=test-key AGENT_PROVIDER_MODEL=stub-model npm run agent:decision\nMARKET_DATA_MODE=mock npm run trade:once\nnpm run trade:once\nMARKET_DATA_MODE=mock npm run trade:once\nMARKET_DATA_MODE=mock GITHUB_CREATE_ISSUES=false npm run report:daily\nMARKET_DATA_MODE=mock GITHUB_CREATE_ISSUES=false npm run report:monthly\nnpm run report:trade-run\n```\n\nExpected result:\n\n- `npm run trade:once` prints a dry-run JSON plan that includes `marketDataSource`, selected ticker snapshots, a `portfolio` snapshot, and per-target `decisions`.\n- `MARKET_DATA_MODE=mock npm run agent:decision` prints a Korean dry-run summary plus a JSON payload with a normalized `snapshot`, validated `decision`, validated `execution` record, persisted file paths, and no order placement.\n- `MARKET_DATA_MODE=mock npm run report:agent-trade-run` writes `artifacts/agent-trade-run/result.json`, `summary.md`, and `status.json`, and copies the latest persisted agent snapshot/decision/execution/state JSON files into the same artifact bundle.\n- `MARKET_DATA_MODE=mock AGENT_DECISION_PROVIDER=openai-compatible ... npm run agent:decision` either records a model-backed dry-run decision or fails closed before execution persistence unless mock fallback is explicitly enabled.\n- The agent run writes `snapshots/latest.json`, `decisions/latest.json`, `executions/latest.json`, and `state/latest.json` plus dated files beneath `artifacts/agent-decision/`.\n- Each decision now includes English internal reasoning/risk/provider metadata plus a Korean `userFacing` summary block for CLI/reporting adapters.\n- `npm run coinone:doctor` prints the vendored Coinone CLI runtime/auth health status.\n- `MARKET_DATA_MODE=mock npm run trade:once` returns `hold` decisions because mock mode does not read private account endpoints.\n- `MARKET_DATA_MODE=mock npm run trade:once` prints the same dry-run structure using deterministic local fixture data only.\n- `MARKET_DATA_MODE=mock GITHUB_CREATE_ISSUES=false npm run report:daily` prints JSON metadata with a markdown draft path plus action-needed reasons instead of creating a GitHub issue.\n- `MARKET_DATA_MODE=mock GITHUB_CREATE_ISSUES=false npm run report:monthly` does the same for the monthly issue format.\n\nTo enable automatic GitHub issue creation and Slack link delivery:\n\n```bash\nGITHUB_REPOSITORY=owner/repo \\\nGITHUB_TOKEN=your-github-token \\\nSLACK_WEBHOOK_URL=https://hooks.slack.com/services/... \\\nMARKET_DATA_MODE=mock \\\nnpm run report:daily\n```\n\nThis still does not place orders; it only creates dry-run report drafts and optional GitHub issues around the simulated trade plan.\n\nTo run the same agent-driven dry-run in GitHub Actions:\n\n1. Open the `Agent Trade Run` workflow.\n2. Leave `agent_decision_provider=mock` for the safest default, or switch to `openai-compatible` only after setting `AGENT_PROVIDER_ENDPOINT`, `AGENT_PROVIDER_MODEL`, and optional prompt/runtime vars in repository variables plus `AGENT_PROVIDER_API_KEY` in repository secrets.\n3. Trigger the workflow and download the `agent-trade-run-artifacts` bundle to inspect the Korean summary and copied decision/execution JSON files.\n\nTo enable account-based 판단 in dry-run mode:\n\n```bash\nCOINONE_ACCESS_TOKEN=your-access-token \\\nCOINONE_SECRET_KEY=your-secret-key \\\nnpm run trade:once\n```\n\nThis still does not place orders; it only allows `coinone --json auth status`, `coinone --json balances list`, and `coinone --json orders completed` to inform the decision.\n\n### Recommended minimum `.env`\n\nFor most users, these are enough:\n\n```bash\nDRY_RUN=true\nENABLE_LIVE_TRADING=false\nSELECTION_MODE=allowlist\nTRADE_TARGETS=USDC\nRISK_PROFILE=balanced\nCOINONE_ACCESS_TOKEN=...\nCOINONE_SECRET_KEY=...\nSLACK_WEBHOOK_URL=...\nGITHUB_REPOSITORY=owner/repo\n```\n\nEverything else in `.env.example` is optional or advanced.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2sem%2Fcoinone-autotrader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2sem%2Fcoinone-autotrader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2sem%2Fcoinone-autotrader/lists"}