Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f3169e72a | |||
| 8c39d41985 | |||
| b3feec08db | |||
| 347c9546ed |
@@ -91,7 +91,7 @@ jobs:
|
||||
| tr '{' '\n' \
|
||||
| grep "\"name\":\"$asset_name\"" \
|
||||
| sed -n 's/.*"id":[[:space:]]*\([0-9][0-9]*\).*/\1/p' \
|
||||
| head -n 1)"
|
||||
| head -n 1 || true)"
|
||||
if [ -n "$asset_id" ]; then
|
||||
curl -fsS -X DELETE "$upload_url/$asset_id" \
|
||||
-H "Authorization: token $GITEA_TOKEN"
|
||||
|
||||
Generated
+1
-1
@@ -667,7 +667,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openstock"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"encoding_rs",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "openstock"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -57,8 +57,8 @@ curl -fsSL https://git.hananakick.cc/Autotrade/openstock/raw/branch/main/scripts
|
||||
Gitea Actions가 활성화된 저장소에서는 push 시 자동으로 CI가 실행됩니다. `main` branch push는 테스트와 release 빌드 검증만 수행하고, `v*` tag push는 Gitea Release를 만들고 Linux x86_64 바이너리를 asset으로 등록합니다.
|
||||
|
||||
```bash
|
||||
git tag v0.2.0
|
||||
git push origin main v0.2.0
|
||||
git tag v0.2.1
|
||||
git push origin main v0.2.1
|
||||
```
|
||||
|
||||
필요 조건:
|
||||
@@ -174,6 +174,15 @@ docker compose logs --tail=120 openstock-runner
|
||||
| `status` | string | 항상 `error`입니다. |
|
||||
| `message` | string | 실패 원인 메시지입니다. |
|
||||
|
||||
## Agent CLI Skill
|
||||
|
||||
에이전트는 별도 MCP 서버나 plugin wrapper 없이 `openstock` CLI를 직접 실행하는 전략을 사용합니다.
|
||||
|
||||
| Document | Purpose |
|
||||
| --- | --- |
|
||||
| `skills/openstock-agent-cli/SKILL.md` | 에이전트가 따라야 할 실행 전략, 출력 해석 규칙, 주문 안전 규칙 |
|
||||
| `skills/openstock-agent-cli/references/commands/` | CLI depth별 명령 설명과 IO 계약 |
|
||||
|
||||
### Command Output Fields
|
||||
|
||||
#### `version`
|
||||
@@ -259,6 +268,19 @@ docker compose logs --tail=120 openstock-runner
|
||||
| `reuters_code` | string | Reuters style code입니다. 없으면 빈 문자열일 수 있습니다. |
|
||||
| `url` | string | Naver 모바일 종목 페이지 URL입니다. |
|
||||
|
||||
#### `score set`, `score get`, `score list`, `score delete`
|
||||
|
||||
| Field | Type | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `path` | string | 종목 평가 점수를 저장하는 파일 경로입니다. 기본값은 `~/.config/openstock/scores.json`입니다. |
|
||||
| `symbol` | string | 점수를 매긴 종목코드 또는 종목 ID입니다. 영문자는 대문자로 정규화됩니다. |
|
||||
| `score` | number | 종목 평가 점수입니다. 0은 최저, 100은 최고입니다. |
|
||||
| `updated_at_unix` | number | 점수를 저장하거나 갱신한 Unix timestamp(초)입니다. |
|
||||
| `count` | number | `score list`가 반환한 저장 점수 개수입니다. |
|
||||
| `scores` | array | `score list`가 반환한 점수 목록입니다. 점수 내림차순, 종목 ID 오름차순으로 정렬됩니다. |
|
||||
| `deleted` | boolean | `score delete`에서 저장된 점수가 실제로 삭제되었는지 여부입니다. |
|
||||
| `removed` | object/null | `score delete`에서 삭제된 기존 점수 기록입니다. |
|
||||
|
||||
#### `universe sync`, `universe status`
|
||||
|
||||
| Field | Type | Meaning |
|
||||
@@ -557,6 +579,7 @@ cp -R .openstock/* ~/.config/openstock/cache/
|
||||
|
||||
| Path | Writer | Reader | Retention | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `~/.config/openstock/scores.json` | `score set`, `score delete` | `score get`, `score list` | protected | 종목 ID별 0~100 평가 점수와 갱신시각입니다. `.env`와 같은 설정 디렉터리에 저장됩니다. |
|
||||
| `~/.config/openstock/cache/universe/kind/latest.json` | `universe sync` | `universe status/list/chunks/validate` | protected | KIND 상장법인목록 최신 normalized stock list입니다. |
|
||||
| `~/.config/openstock/cache/universe/kind/meta.json` | `universe sync` | `universe status/*` | protected | universe cache metadata입니다. |
|
||||
| `~/.config/openstock/cache/universe/kind/YYYY-MM-DD.json` | `universe sync` | audit/manual use | max 7 files or 25MB | 날짜별 universe snapshot입니다. |
|
||||
@@ -652,6 +675,54 @@ Naver 모바일 주식 검색 API로 종목 후보를 검색합니다.
|
||||
|
||||
`stocks` 항목은 가능한 경우 `code`, `name`, `market`, `market_code`, `nation_code`, `category`, `reuters_code`, `url`을 포함합니다.
|
||||
|
||||
### `openstock score set <symbol> <score>`
|
||||
|
||||
종목 ID에 0~100점 평가 점수를 저장하거나 갱신합니다.
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Input | `symbol`, `score` |
|
||||
| File read/write | `~/.config/openstock/scores.json` |
|
||||
| Output fields | `path`, `symbol`, `score`, `updated_at_unix` |
|
||||
| Raw | `null` |
|
||||
| Side effect | 종목 평가 점수 파일을 생성하거나 갱신합니다. |
|
||||
|
||||
### `openstock score get <symbol>`
|
||||
|
||||
종목 ID의 저장된 평가 점수를 조회합니다.
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Input | `symbol` |
|
||||
| File read | `~/.config/openstock/scores.json` |
|
||||
| Output fields | `path`, `symbol`, `score`, `updated_at_unix` |
|
||||
| Raw | `null` |
|
||||
| Side effect | 없음 |
|
||||
|
||||
### `openstock score list`
|
||||
|
||||
저장된 종목 평가 점수 목록을 점수 내림차순으로 조회합니다.
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Input | 없음 |
|
||||
| File read | `~/.config/openstock/scores.json` |
|
||||
| Output fields | `path`, `count`, `scores` |
|
||||
| Raw | `null` |
|
||||
| Side effect | 없음 |
|
||||
|
||||
### `openstock score delete <symbol>`
|
||||
|
||||
종목 ID의 저장된 평가 점수를 삭제합니다.
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Input | `symbol` |
|
||||
| File read/write | `~/.config/openstock/scores.json` |
|
||||
| Output fields | `path`, `symbol`, `deleted`, `removed` |
|
||||
| Raw | `null` |
|
||||
| Side effect | 저장된 점수가 있으면 해당 기록을 삭제합니다. |
|
||||
|
||||
### `openstock universe sync [--force]`
|
||||
|
||||
KIND 상장법인목록을 받아 stock universe cache를 갱신합니다.
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: openstock-agent-cli
|
||||
description: Use when operating OpenStock through its CLI for Korean stock search, KIS market/account/order commands, KIND universe scans, OpenDART disclosures, cache management, or agent-safe trading evidence workflows. This skill intentionally avoids MCP/plugin wrappers and relies on direct CLI execution.
|
||||
---
|
||||
|
||||
# OpenStock Agent CLI Skill
|
||||
|
||||
Use this skill when an agent needs Korean stock search, market data, KIS account/order access, KIND universe data, or OpenDART disclosure evidence from this repository.
|
||||
|
||||
## Strategy
|
||||
|
||||
Do not start an MCP server or create a plugin wrapper. Use the installed `openstock` CLI directly and treat its stdout/stderr JSON as the tool contract.
|
||||
|
||||
The CLI is the single integration surface for humans and agents:
|
||||
|
||||
```bash
|
||||
openstock search 삼성전자
|
||||
openstock market 005930
|
||||
openstock dart show 005930 --from 20260601 --to 20260609
|
||||
openstock account status
|
||||
```
|
||||
|
||||
## Runtime Model
|
||||
|
||||
- `openstock` is a normal process per command invocation.
|
||||
- It is not a daemon.
|
||||
- It does not open a port.
|
||||
- It reads config and cache from `~/.config/openstock`.
|
||||
- It prints one JSON object to stdout on success.
|
||||
- It prints one JSON object to stderr on failure.
|
||||
|
||||
## Output Contract
|
||||
|
||||
Every command returns explained JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "logical command name",
|
||||
"description": "human and agent readable result description",
|
||||
"fields": [
|
||||
{
|
||||
"name": "field_name",
|
||||
"description": "field meaning",
|
||||
"value": "actual value"
|
||||
}
|
||||
],
|
||||
"raw": null
|
||||
}
|
||||
```
|
||||
|
||||
Agent behavior:
|
||||
|
||||
- Read `fields[].description` before interpreting `fields[].value`.
|
||||
- Prefer typed commands over `api call` when a typed command exists.
|
||||
- Use `raw` only when the command explicitly returns raw API data.
|
||||
- Preserve numeric strings from broker APIs; do not coerce them unless calculation is required.
|
||||
- Treat stderr JSON as a command failure even when it is parseable.
|
||||
|
||||
## Safety Rules
|
||||
|
||||
- `order buy` and `order sell` are live KIS orders.
|
||||
- Do not place orders unless the user explicitly requests a real order in the current task.
|
||||
- Before any order, check `account status`, target symbol evidence, quantity, order type, and price.
|
||||
- For evidence gathering, use read-only commands: `search`, `market`, `market history`, `dart`, `universe`, `account status`, `order status`.
|
||||
- Never infer that a missing cache means missing data; run the relevant `sync` command when appropriate.
|
||||
|
||||
## Command Documentation
|
||||
|
||||
Commands are documented by CLI depth under `references/commands`.
|
||||
|
||||
| Command | Documentation |
|
||||
| --- | --- |
|
||||
| `openstock version` | `references/commands/version/guide.md` |
|
||||
| `openstock update` | `references/commands/update/guide.md` |
|
||||
| `openstock search` | `references/commands/search/guide.md` |
|
||||
| `openstock score *` | `references/commands/score/guide.md` |
|
||||
| `openstock api *` | `references/commands/api/guide.md` |
|
||||
| `openstock account *` | `references/commands/account/guide.md` |
|
||||
| `openstock market *` | `references/commands/market/guide.md` |
|
||||
| `openstock universe *` | `references/commands/universe/guide.md` |
|
||||
| `openstock dart *` | `references/commands/dart/guide.md` |
|
||||
| `openstock order *` | `references/commands/order/guide.md` |
|
||||
| `openstock cache *` | `references/commands/cache/guide.md` |
|
||||
|
||||
## Recommended Evidence Flow
|
||||
|
||||
```bash
|
||||
openstock api login
|
||||
openstock universe sync
|
||||
openstock dart sync
|
||||
openstock search 삼성전자
|
||||
openstock market 005930
|
||||
openstock market history 005930 --from 20260101 --to 20260609
|
||||
openstock dart show 005930 --from 20260601 --to 20260609 --index 1
|
||||
openstock account status
|
||||
```
|
||||
|
||||
This flow gathers evidence. It is not sufficient by itself for unattended trading.
|
||||
@@ -0,0 +1,41 @@
|
||||
# `openstock account`
|
||||
|
||||
## Purpose
|
||||
|
||||
Read KIS account state for the configured live account.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock account status` | Show balance and holdings. |
|
||||
|
||||
## `account status`
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
openstock account status
|
||||
```
|
||||
|
||||
### IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | `KIS_ACCESS_TOKEN`, `KIS_APPKEY`, `KIS_APPSECRET`, `KIS_ACCOUNT` |
|
||||
| External IO | KIS balance inquiry endpoint. |
|
||||
| File IO | `~/.config/openstock/.env` read. |
|
||||
| Side effect | none |
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker API used for inquiry. |
|
||||
| `account` | Queried account number. |
|
||||
| `balance` | Cash, total evaluated asset amount, profit/loss, and account summary values. |
|
||||
| `holdings` | Currently held stock list. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use this before any proposed trade to check cash, holdings, and orderable quantity context.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock account status`
|
||||
|
||||
Purpose: query balance and holdings for the configured KIS account.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock account status
|
||||
```
|
||||
|
||||
Reads: `KIS_ACCESS_TOKEN`, `KIS_APPKEY`, `KIS_APPSECRET`, `KIS_ACCOUNT`.
|
||||
|
||||
External IO: KIS balance inquiry.
|
||||
|
||||
Output fields: `broker`, `account`, `balance`, `holdings`.
|
||||
|
||||
Agent rule: run before any trade recommendation or live order.
|
||||
@@ -0,0 +1,19 @@
|
||||
# `openstock api call`
|
||||
|
||||
Purpose: directly call a KIS GET endpoint with access-token headers.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock api call /uapi/... --param tr_id=... --param KEY=VALUE
|
||||
```
|
||||
|
||||
Inputs: `endpoint`, repeated `--param KEY=VALUE`.
|
||||
|
||||
Reads: KIS credentials and access token from config/env.
|
||||
|
||||
External IO: KIS endpoint GET.
|
||||
|
||||
Output fields: `broker`, `endpoint`, `params`, `request_semantics`, `response`, `response_semantics`.
|
||||
|
||||
Agent rule: prefer typed commands; use this only for endpoints not yet implemented as stable commands.
|
||||
@@ -0,0 +1,91 @@
|
||||
# `openstock api`
|
||||
|
||||
## Purpose
|
||||
|
||||
Manage broker API metadata, KIS login, and raw endpoint calls.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock api list` | Show registered broker APIs and their capabilities. |
|
||||
| `openstock api login [--appkey KEY] [--appsecret SECRET] [--force]` | Issue or reuse a KIS access token. |
|
||||
| `openstock api call <endpoint> --param KEY=VALUE` | Direct KIS GET endpoint call with token headers. |
|
||||
|
||||
## `api list`
|
||||
|
||||
### IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| External IO | none |
|
||||
| File IO | none |
|
||||
| Side effect | none |
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `count` | Number of registered broker APIs. |
|
||||
| `apis` | Broker metadata, credential requirements, capability catalog, IO contract, and side effects. |
|
||||
|
||||
## `api login`
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
openstock api login
|
||||
openstock api login --force
|
||||
```
|
||||
|
||||
### IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | `KIS_APPKEY`, `KIS_APPSECRET`, `KIS_ACCESS_TOKEN`, `KIS_ACCESS_TOKEN_EXPIRED_AT` |
|
||||
| Config write | `~/.config/openstock/.env` auth state. |
|
||||
| External IO | KIS token endpoint only when token is missing, expired, or `--force` is used. |
|
||||
| Side effect | Writes auth token state. |
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker API used for login. |
|
||||
| `status` | Login result. |
|
||||
| `force` | Whether token refresh was forced. |
|
||||
| `credential_source` | Whether credentials came from CLI arguments or config. |
|
||||
| `token_storage` | Token storage path and env keys. |
|
||||
| `side_effect` | Auth-state write indicator. |
|
||||
|
||||
## `api call`
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
openstock api call /uapi/... --param tr_id=... --param KEY=VALUE
|
||||
```
|
||||
|
||||
### IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | `KIS_ACCESS_TOKEN`, `KIS_APPKEY`, `KIS_APPSECRET` |
|
||||
| External IO | KIS endpoint GET. |
|
||||
| File IO | `~/.config/openstock/.env` read. |
|
||||
| Side effect | Endpoint dependent. |
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker used for the direct call. |
|
||||
| `endpoint` | Requested endpoint. |
|
||||
| `params` | Request parameters. |
|
||||
| `request_semantics` | How params map to headers/query. |
|
||||
| `response` | Parsed API response. |
|
||||
| `response_semantics` | Explanation of response meaning. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Prefer typed commands. Use `api call` only for inspection or endpoints not yet bound as typed commands.
|
||||
@@ -0,0 +1,15 @@
|
||||
# `openstock api list`
|
||||
|
||||
Purpose: return registered broker APIs, credential requirements, capabilities, IO contracts, and side-effect metadata.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock api list
|
||||
```
|
||||
|
||||
Inputs: none.
|
||||
|
||||
Output fields: `count`, `apis`.
|
||||
|
||||
Agent rule: use this to discover broker capability metadata; it performs no external IO.
|
||||
@@ -0,0 +1,21 @@
|
||||
# `openstock api login`
|
||||
|
||||
Purpose: issue or reuse a KIS live API access token.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock api login
|
||||
openstock api login --force
|
||||
openstock api login --appkey KEY --appsecret SECRET
|
||||
```
|
||||
|
||||
Inputs: optional `--appkey`, `--appsecret`, `--force`.
|
||||
|
||||
Reads: `KIS_APPKEY`, `KIS_APPSECRET`, existing token values.
|
||||
|
||||
Writes: `~/.config/openstock/.env` token state.
|
||||
|
||||
Output fields: `broker`, `status`, `force`, `credential_source`, `token_storage`, `side_effect`.
|
||||
|
||||
Agent rule: do not force refresh unless the user asks or an API call fails because the token is invalid.
|
||||
@@ -0,0 +1,39 @@
|
||||
# `openstock cache`
|
||||
|
||||
## Purpose
|
||||
|
||||
Inspect and prune local cache under `~/.config/openstock/cache`.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock cache status` | Show cache size and namespace summary. |
|
||||
| `openstock cache prune [--dry-run]` | Apply cache retention policy. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| File read | Cache directories. |
|
||||
| File delete | Old cache files unless `--dry-run` is used. |
|
||||
| External IO | none |
|
||||
| Side effect | `prune` deletes files unless dry-run. |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `root` | Cache root path. |
|
||||
| `exists` | Whether cache root exists. |
|
||||
| `total_files` | Number of cache files. |
|
||||
| `total_bytes` | Total cache size. |
|
||||
| `namespaces` | Cache namespace summaries. |
|
||||
| `dry_run` | Whether prune only reported actions. |
|
||||
| `deleted_files` | Number of deleted files. |
|
||||
| `deleted_bytes` | Bytes removed. |
|
||||
| `reports` | Prune reports by namespace. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Run `cache prune --dry-run` before destructive pruning unless the user clearly asks to clean cache.
|
||||
@@ -0,0 +1,18 @@
|
||||
# `openstock cache prune`
|
||||
|
||||
Purpose: apply cache retention policy.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock cache prune --dry-run
|
||||
openstock cache prune
|
||||
```
|
||||
|
||||
Reads: `~/.config/openstock/cache`.
|
||||
|
||||
Deletes: old cache files unless `--dry-run` is set.
|
||||
|
||||
Output fields: `dry_run`, `deleted_files`, `deleted_bytes`, `reports`.
|
||||
|
||||
Agent rule: run `--dry-run` first unless the user explicitly requests cleanup.
|
||||
@@ -0,0 +1,15 @@
|
||||
# `openstock cache status`
|
||||
|
||||
Purpose: inspect local cache size and namespace summary.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock cache status
|
||||
```
|
||||
|
||||
Reads: `~/.config/openstock/cache`.
|
||||
|
||||
Output fields: `root`, `exists`, `total_files`, `total_bytes`, `namespaces`.
|
||||
|
||||
Agent rule: use before cache cleanup or when diagnosing stale local data.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock dart corp`
|
||||
|
||||
Purpose: resolve a KRX stock symbol to an OpenDART corp code.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart corp 005930
|
||||
```
|
||||
|
||||
Input: `symbol`.
|
||||
|
||||
Reads: OpenDART corp code cache; refreshes on miss when needed.
|
||||
|
||||
Output fields: `stock_code`, `corp_code`, `corp_name`, `modify_date`.
|
||||
|
||||
Agent rule: use when an OpenDART command needs an explicit corp code.
|
||||
@@ -0,0 +1,20 @@
|
||||
# `openstock dart disclosures`
|
||||
|
||||
Purpose: query disclosure lists from OpenDART.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart disclosures 005930 --from 20260601 --to 20260609
|
||||
openstock dart disclosures --corp-code 00126380 --page-count 50
|
||||
```
|
||||
|
||||
Inputs: optional `symbol`, `--corp-code`, `--from`, `--to`, `--corp-cls`, `--page-no`, `--page-count`.
|
||||
|
||||
Reads: `OPENDART_API_KEY`; corp-code cache when resolving a symbol.
|
||||
|
||||
External IO: OpenDART list API.
|
||||
|
||||
Output fields: `query`, `resolved`, `disclosures`.
|
||||
|
||||
Agent rule: use for disclosure evidence lists without fetching document text.
|
||||
@@ -0,0 +1,19 @@
|
||||
# `openstock dart document`
|
||||
|
||||
Purpose: fetch and extract text from a DART disclosure document by receipt number.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart document 20260609000000 --max-chars 20000
|
||||
```
|
||||
|
||||
Inputs: `rcept_no`, optional `--force`, `--max-chars`.
|
||||
|
||||
Reads: `OPENDART_API_KEY`.
|
||||
|
||||
Writes: document ZIP cache.
|
||||
|
||||
Output fields: document metadata and extracted text.
|
||||
|
||||
Agent rule: use `--max-chars` to cap large documents.
|
||||
@@ -0,0 +1,43 @@
|
||||
# `openstock dart`
|
||||
|
||||
## Purpose
|
||||
|
||||
Query OpenDART listed-company mappings, disclosure lists, and disclosure documents.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock dart sync [--force]` | Refresh OpenDART corp code cache. |
|
||||
| `openstock dart status` | Show corp code cache status. |
|
||||
| `openstock dart corp <symbol>` | Resolve KRX symbol to DART corp code. |
|
||||
| `openstock dart disclosures [symbol] [--corp-code CODE] [--from YYYYMMDD] [--to YYYYMMDD] [--corp-cls Y|K|N|E] [--page-no N] [--page-count N]` | Query disclosure list. |
|
||||
| `openstock dart document <rcept_no> [--force] [--max-chars N]` | Fetch disclosure document text. |
|
||||
| `openstock dart show <symbol> [--from YYYYMMDD] [--to YYYYMMDD] [--index N] [--page-count N] [--force] [--max-chars N]` | Query disclosures for a symbol and fetch one selected document. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | `OPENDART_API_KEY` for OpenDART API calls. |
|
||||
| External IO | OpenDART corp code, list, and document endpoints. |
|
||||
| File read/write | `~/.config/openstock/cache/opendart`. |
|
||||
| Side effect | `sync`, `document`, and `show` can write cache. |
|
||||
|
||||
## Important Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `stock_code` | KRX stock code. |
|
||||
| `corp_code` | OpenDART 8-digit company code. |
|
||||
| `corp_name` | OpenDART company name. |
|
||||
| `modify_date` | Corp code mapping modification date. |
|
||||
| `query` | Disclosure query sent to OpenDART. |
|
||||
| `resolved` | Symbol/corp code resolution details. |
|
||||
| `disclosures` | Disclosure list. |
|
||||
| `selected` | Disclosure selected by `--index`. |
|
||||
| `document` | Disclosure document metadata and extracted text. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use `dart show` for the common workflow: symbol to disclosures to selected document. Use `dart disclosures` when only the list is needed.
|
||||
@@ -0,0 +1,19 @@
|
||||
# `openstock dart show`
|
||||
|
||||
Purpose: query disclosures for a symbol and fetch the selected disclosure document.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart show 005930 --from 20260601 --to 20260609 --index 1
|
||||
```
|
||||
|
||||
Inputs: `symbol`, optional `--from`, `--to`, `--index`, `--page-count`, `--force`, `--max-chars`.
|
||||
|
||||
Reads: `OPENDART_API_KEY`; corp-code and document cache.
|
||||
|
||||
External IO: OpenDART list and document APIs.
|
||||
|
||||
Output fields: `query`, `resolved`, `disclosures`, `selected`, `document`.
|
||||
|
||||
Agent rule: preferred command when the task asks for a specific stock's latest disclosure and contents.
|
||||
@@ -0,0 +1,15 @@
|
||||
# `openstock dart status`
|
||||
|
||||
Purpose: inspect OpenDART corp code cache status.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart status
|
||||
```
|
||||
|
||||
Reads: OpenDART corp code cache.
|
||||
|
||||
Output fields: source/cache metadata and corp count.
|
||||
|
||||
Agent rule: if cache is missing, run `openstock dart sync`.
|
||||
@@ -0,0 +1,18 @@
|
||||
# `openstock dart sync`
|
||||
|
||||
Purpose: refresh OpenDART listed-company corp code mapping cache.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock dart sync
|
||||
openstock dart sync --force
|
||||
```
|
||||
|
||||
Reads: `OPENDART_API_KEY`.
|
||||
|
||||
Writes: `~/.config/openstock/cache/opendart/corp_codes.json`.
|
||||
|
||||
Output fields: source/cache metadata and corp count.
|
||||
|
||||
Agent rule: run when corp-code cache is missing, stale, or explicitly requested.
|
||||
@@ -0,0 +1,32 @@
|
||||
# OpenStock CLI Command Map
|
||||
|
||||
This directory mirrors the `openstock` CLI command depth for agent execution.
|
||||
|
||||
| CLI Depth | Folder |
|
||||
| --- | --- |
|
||||
| `openstock version` | `version/` |
|
||||
| `openstock update` | `update/` |
|
||||
| `openstock search` | `search/` |
|
||||
| `openstock score ...` | `score/` |
|
||||
| `openstock api ...` | `api/` |
|
||||
| `openstock account ...` | `account/` |
|
||||
| `openstock market ...` | `market/` |
|
||||
| `openstock universe ...` | `universe/` |
|
||||
| `openstock dart ...` | `dart/` |
|
||||
| `openstock order ...` | `order/` |
|
||||
| `openstock cache ...` | `cache/` |
|
||||
|
||||
Subcommands also have leaf folders matching CLI depth, for example:
|
||||
|
||||
| CLI Depth | Folder |
|
||||
| --- | --- |
|
||||
| `openstock api login` | `api/login/` |
|
||||
| `openstock score set` | `score/set/` |
|
||||
| `openstock account status` | `account/status/` |
|
||||
| `openstock market history` | `market/history/` |
|
||||
| `openstock universe chunks` | `universe/chunks/` |
|
||||
| `openstock dart show` | `dart/show/` |
|
||||
| `openstock order buy` | `order/buy/` |
|
||||
| `openstock cache prune` | `cache/prune/` |
|
||||
|
||||
Agents should read `../../SKILL.md` first, then open the folder matching the command depth they intend to run.
|
||||
@@ -0,0 +1,60 @@
|
||||
# `openstock market`
|
||||
|
||||
## Purpose
|
||||
|
||||
Read KIS market data for a stock symbol.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock market <symbol>` | Current price and company/basic information. |
|
||||
| `openstock market history <symbol> --from YYYYMMDD --to YYYYMMDD [--period D|W|M|Y] [--raw-price]` | OHLCV price history. |
|
||||
|
||||
## `market <symbol>`
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker API used for data. |
|
||||
| `symbol` | Queried KRX symbol. |
|
||||
| `price` | Current price and market values. |
|
||||
| `company` | Stock/company basic information. |
|
||||
|
||||
## `market history`
|
||||
|
||||
### Input
|
||||
|
||||
| Input | Meaning |
|
||||
| --- | --- |
|
||||
| `symbol` | KRX symbol. |
|
||||
| `--from` | Start date in `YYYYMMDD`. |
|
||||
| `--to` | End date in `YYYYMMDD`. |
|
||||
| `--period` | `D`, `W`, `M`, or `Y`; default `D`. |
|
||||
| `--raw-price` | Use original prices instead of adjusted prices. |
|
||||
|
||||
### Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker API used for data. |
|
||||
| `symbol` | Queried KRX symbol. |
|
||||
| `period` | Candle period. |
|
||||
| `date_range` | Requested date range. |
|
||||
| `adjusted` | Whether adjusted price was requested. |
|
||||
| `count` | Number of candles. |
|
||||
| `candles` | Date-ascending OHLCV values. Numeric values may be strings. |
|
||||
| `summary` | KIS summary data. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | KIS app credentials and access token. |
|
||||
| External IO | KIS domestic stock quote/history endpoints. |
|
||||
| Side effect | none |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use `market` for current context and `market history` for price movement evidence. Always resolve ambiguous names with `search` first.
|
||||
@@ -0,0 +1,20 @@
|
||||
# `openstock market history`
|
||||
|
||||
Purpose: query OHLCV price history for a stock.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock market history 005930 --from 20260101 --to 20260609
|
||||
openstock market history 005930 --from 20260101 --to 20260609 --period W
|
||||
```
|
||||
|
||||
Inputs: `symbol`, `--from`, `--to`, optional `--period`, `--raw-price`.
|
||||
|
||||
Reads: KIS credentials and access token.
|
||||
|
||||
External IO: KIS price history endpoint.
|
||||
|
||||
Output fields: `broker`, `symbol`, `period`, `date_range`, `adjusted`, `count`, `candles`, `summary`.
|
||||
|
||||
Agent rule: use for price movement evidence; keep numeric strings intact unless calculating.
|
||||
@@ -0,0 +1,20 @@
|
||||
# `openstock order buy`
|
||||
|
||||
Purpose: place a live KIS domestic stock buy order.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock order buy 005930 --qty 1 --price 70000
|
||||
openstock order buy 005930 --qty 1 --market
|
||||
```
|
||||
|
||||
Inputs: `symbol`, `--qty`, one of `--price` or `--market`.
|
||||
|
||||
External IO: KIS live order endpoint.
|
||||
|
||||
Side effect: live financial buy order.
|
||||
|
||||
Output fields: `broker`, `side`, `symbol`, `qty`, `order_type`, `price`, `order`.
|
||||
|
||||
Agent rule: only run after explicit current-user approval for a real order.
|
||||
@@ -0,0 +1,52 @@
|
||||
# `openstock order`
|
||||
|
||||
## Purpose
|
||||
|
||||
Place and query live KIS domestic stock orders.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock order buy <symbol> --qty QTY (--price PRICE|--market)` | Place a live buy order. |
|
||||
| `openstock order sell <symbol> --qty QTY (--price PRICE|--market)` | Place a live sell order. |
|
||||
| `openstock order status [order_no] [--from YYYYMMDD] [--to YYYYMMDD]` | Query order/execution status. |
|
||||
|
||||
## Safety
|
||||
|
||||
`buy` and `sell` are live financial orders. Do not run them unless the user explicitly asks for a real order in the current task.
|
||||
|
||||
Before placing an order:
|
||||
|
||||
1. Run `openstock account status`.
|
||||
2. Confirm the symbol with `search` or `market`.
|
||||
3. Confirm side, quantity, order type, and price.
|
||||
4. Prefer `order status` for verification after order placement.
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| Env read | `KIS_ACCESS_TOKEN`, `KIS_APPKEY`, `KIS_APPSECRET`, `KIS_ACCOUNT` |
|
||||
| External IO | KIS order and order inquiry endpoints. |
|
||||
| Side effect | `buy` and `sell` place live orders. `status` is read-only. |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `broker` | Broker used for order. |
|
||||
| `side` | `buy` or `sell`. |
|
||||
| `symbol` | Ordered symbol. |
|
||||
| `qty` | Order quantity. |
|
||||
| `order_type` | `limit` or `market`. |
|
||||
| `price` | Limit price or market-order price representation. |
|
||||
| `order` | Broker order result. |
|
||||
| `account` | Account queried for status. |
|
||||
| `order_no` | Requested order number filter. |
|
||||
| `orders` | Order/execution list. |
|
||||
| `summary` | Broker summary values. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
For analysis-only tasks, never use `buy` or `sell`. Use `order status` only when order history is relevant.
|
||||
@@ -0,0 +1,20 @@
|
||||
# `openstock order sell`
|
||||
|
||||
Purpose: place a live KIS domestic stock sell order.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock order sell 005930 --qty 1 --price 70000
|
||||
openstock order sell 005930 --qty 1 --market
|
||||
```
|
||||
|
||||
Inputs: `symbol`, `--qty`, one of `--price` or `--market`.
|
||||
|
||||
External IO: KIS live order endpoint.
|
||||
|
||||
Side effect: live financial sell order.
|
||||
|
||||
Output fields: `broker`, `side`, `symbol`, `qty`, `order_type`, `price`, `order`.
|
||||
|
||||
Agent rule: only run after explicit current-user approval for a real order.
|
||||
@@ -0,0 +1,18 @@
|
||||
# `openstock order status`
|
||||
|
||||
Purpose: query KIS order and execution status.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock order status
|
||||
openstock order status 1234567890 --from 20260601 --to 20260609
|
||||
```
|
||||
|
||||
Inputs: optional `order_no`, `--from`, `--to`.
|
||||
|
||||
External IO: KIS order inquiry endpoint.
|
||||
|
||||
Output fields: `broker`, `account`, `order_no`, `orders`, `summary`.
|
||||
|
||||
Agent rule: read-only; use after order placement or when auditing order history.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock score delete`
|
||||
|
||||
Purpose: delete a saved stock evaluation score.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock score delete 005930
|
||||
```
|
||||
|
||||
Inputs: `symbol`.
|
||||
|
||||
Writes: `~/.config/openstock/scores.json` when a record exists.
|
||||
|
||||
Output fields: `path`, `symbol`, `deleted`, `removed`.
|
||||
|
||||
Agent rule: deletion changes local evaluation state; run only when requested.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock score get`
|
||||
|
||||
Purpose: read a saved stock evaluation score.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock score get 005930
|
||||
```
|
||||
|
||||
Inputs: `symbol`.
|
||||
|
||||
Reads: `~/.config/openstock/scores.json`.
|
||||
|
||||
Output fields: `path`, `symbol`, `score`, `updated_at_unix`.
|
||||
|
||||
Agent rule: if the command fails with no saved score, do not infer a score of 0.
|
||||
@@ -0,0 +1,41 @@
|
||||
# `openstock score`
|
||||
|
||||
## Purpose
|
||||
|
||||
Store and query local stock evaluation scores by stock ID.
|
||||
|
||||
## Storage
|
||||
|
||||
Scores are stored beside `.env` under the OpenStock config directory:
|
||||
|
||||
```text
|
||||
~/.config/openstock/scores.json
|
||||
```
|
||||
|
||||
Each score is an integer from 0 to 100. `0` is the lowest evaluation and `100` is the highest.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock score set <symbol> <score>` | Save or update a stock score. |
|
||||
| `openstock score get <symbol>` | Read one stock score. |
|
||||
| `openstock score list` | List all saved scores. |
|
||||
| `openstock score delete <symbol>` | Delete one stock score. |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `path` | Score file path. |
|
||||
| `symbol` | Normalized stock ID. |
|
||||
| `score` | 0 to 100 score. |
|
||||
| `updated_at_unix` | Update Unix timestamp in seconds. |
|
||||
| `count` | Number of saved scores. |
|
||||
| `scores` | Score records sorted by score descending. |
|
||||
| `deleted` | Whether a record was deleted. |
|
||||
| `removed` | Deleted record, if any. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use this for user- or strategy-defined evaluation state. Do not treat the score as market evidence unless the workflow defines how it was produced.
|
||||
@@ -0,0 +1,15 @@
|
||||
# `openstock score list`
|
||||
|
||||
Purpose: list saved stock evaluation scores.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock score list
|
||||
```
|
||||
|
||||
Reads: `~/.config/openstock/scores.json`.
|
||||
|
||||
Output fields: `path`, `count`, `scores`.
|
||||
|
||||
Agent rule: scores are sorted by score descending, then symbol ascending.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock score set`
|
||||
|
||||
Purpose: save or update a stock evaluation score.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock score set 005930 87
|
||||
```
|
||||
|
||||
Inputs: `symbol`, `score` from 0 to 100.
|
||||
|
||||
Writes: `~/.config/openstock/scores.json`.
|
||||
|
||||
Output fields: `path`, `symbol`, `score`, `updated_at_unix`.
|
||||
|
||||
Agent rule: use only when the user or scoring workflow has produced a concrete score.
|
||||
@@ -0,0 +1,38 @@
|
||||
# `openstock search`
|
||||
|
||||
## Purpose
|
||||
|
||||
Search stock candidates by name or symbol using Naver mobile stock search.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
openstock search 삼성전자
|
||||
openstock search 005930
|
||||
```
|
||||
|
||||
## Input
|
||||
|
||||
| Input | Meaning |
|
||||
| --- | --- |
|
||||
| `query` | Stock name or stock code. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| External IO | `GET https://m.stock.naver.com/front-api/search/autoComplete` |
|
||||
| File IO | none |
|
||||
| Side effect | none |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `provider` | External data provider. |
|
||||
| `query` | Query submitted by the user/agent. |
|
||||
| `stocks` | Matching stock candidates. Items can include code, name, market, market code, nation code, category, Reuters code, and URL. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use this to resolve a human company name to a tradable symbol before calling `market`, `market history`, or `dart`.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock universe chunks`
|
||||
|
||||
Purpose: divide the stock universe into scan chunks.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock universe chunks --market KOSDAQ --kind common_stock --size 100
|
||||
```
|
||||
|
||||
Inputs: optional `--market`, `--kind`, `--size`.
|
||||
|
||||
Reads: universe cache.
|
||||
|
||||
Output fields: `source`, `cache_date`, `filtered_count`, `chunk_size`, `chunk_count`, `chunks`.
|
||||
|
||||
Agent rule: preferred for full-market scan planning.
|
||||
@@ -0,0 +1,46 @@
|
||||
# `openstock universe`
|
||||
|
||||
## Purpose
|
||||
|
||||
Build and query a local universe of listed Korean stocks from KIND.
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `openstock universe sync [--force]` | Refresh KIND universe cache. |
|
||||
| `openstock universe status` | Show local universe cache status. |
|
||||
| `openstock universe list [--market MARKET] [--kind KIND] [--offset N] [--limit N]` | Page through stocks. |
|
||||
| `openstock universe chunks [--market MARKET] [--kind KIND] [--size N]` | Build scan chunks. |
|
||||
| `openstock universe validate` | Validate expected size and representative symbols. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| External IO | KIND listed company download on sync/cache miss. |
|
||||
| File read/write | `~/.config/openstock/cache/universe/kind`. |
|
||||
| Side effect | `sync` writes cache and prunes old snapshots. Read commands can sync on cache miss. |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `source` | Data source. |
|
||||
| `cache_date` | Cache date. |
|
||||
| `refreshed_at` | Refresh timestamp. |
|
||||
| `refreshed` | Whether command refreshed data. |
|
||||
| `stock_count` | Number of stocks in snapshot. |
|
||||
| `counts_by_market` | Count by market. |
|
||||
| `total_count` | Total stocks before filtering. |
|
||||
| `filtered_count` | Stocks after filter. |
|
||||
| `offset` | Pagination offset. |
|
||||
| `limit` | Pagination limit. |
|
||||
| `stocks` | Normalized stock records. |
|
||||
| `chunk_size` | Requested chunk size. |
|
||||
| `chunk_count` | Number of chunks. |
|
||||
| `chunks` | Scan chunk list. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use `chunks` when scanning many stocks. Do not request the whole universe if a paged or chunked workflow is enough.
|
||||
@@ -0,0 +1,17 @@
|
||||
# `openstock universe list`
|
||||
|
||||
Purpose: page through normalized stock universe records.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock universe list --market KOSPI --kind common_stock --offset 0 --limit 100
|
||||
```
|
||||
|
||||
Inputs: optional `--market`, `--kind`, `--offset`, `--limit`.
|
||||
|
||||
Reads: universe cache; may refresh on cache miss.
|
||||
|
||||
Output fields: `source`, `cache_date`, `total_count`, `filtered_count`, `offset`, `limit`, `stocks`.
|
||||
|
||||
Agent rule: use pagination instead of loading the full universe when possible.
|
||||
@@ -0,0 +1,15 @@
|
||||
# `openstock universe status`
|
||||
|
||||
Purpose: inspect local KIND universe cache status.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock universe status
|
||||
```
|
||||
|
||||
Reads: universe cache.
|
||||
|
||||
Output fields: `source`, `cache_date`, `refreshed_at`, `refreshed`, `stock_count`, `counts_by_market`.
|
||||
|
||||
Agent rule: if cache is missing, run `openstock universe sync`.
|
||||
@@ -0,0 +1,18 @@
|
||||
# `openstock universe sync`
|
||||
|
||||
Purpose: refresh KIND listed stock universe cache.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock universe sync
|
||||
openstock universe sync --force
|
||||
```
|
||||
|
||||
External IO: KIND listed company download.
|
||||
|
||||
Writes: `~/.config/openstock/cache/universe/kind`.
|
||||
|
||||
Output fields: `source`, `cache_date`, `refreshed_at`, `refreshed`, `stock_count`, `counts_by_market`.
|
||||
|
||||
Agent rule: run before broad scans if the cache date matters.
|
||||
@@ -0,0 +1,18 @@
|
||||
# `openstock universe validate`
|
||||
|
||||
Purpose: validate universe size and representative stock expectations.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
openstock universe validate
|
||||
openstock universe validate --expect 005930=삼성전자
|
||||
```
|
||||
|
||||
Inputs: minimum count options and repeated `--expect SYMBOL=NAME`.
|
||||
|
||||
Reads: universe cache.
|
||||
|
||||
Output fields: validation checks and status.
|
||||
|
||||
Agent rule: run after sync when verifying that the cached universe is usable.
|
||||
@@ -0,0 +1,49 @@
|
||||
# `openstock update`
|
||||
|
||||
## Purpose
|
||||
|
||||
Update the installed `openstock` binary from the latest Gitea release asset.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
openstock update
|
||||
openstock update --force
|
||||
```
|
||||
|
||||
## Input
|
||||
|
||||
| Input | Meaning |
|
||||
| --- | --- |
|
||||
| `--force` | Reinstall from the latest release asset even when the current version matches. |
|
||||
| `OPENSTOCK_INSTALL_DIR` | Optional install directory override. |
|
||||
| `OPENSTOCK_RELEASE_API_URL` | Optional release API URL override. |
|
||||
| `OPENSTOCK_RELEASE_ASSET_SUFFIX` | Optional asset suffix override. |
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| External IO | Gitea latest release API and selected release asset download. |
|
||||
| File write | Installed `openstock` binary. |
|
||||
| Side effect | Replaces the installed binary when newer or forced. |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `release_api_url` | Gitea release API endpoint used for update discovery. |
|
||||
| `current_version` | Version of the running binary. |
|
||||
| `latest_version` | Version parsed from latest release tag. |
|
||||
| `release_tag` | Latest release tag. |
|
||||
| `release_url` | Human-readable release page. |
|
||||
| `asset_name` | Release asset selected for installation. |
|
||||
| `asset_url` | Asset download URL. |
|
||||
| `install_dir` | Directory where the binary is installed. |
|
||||
| `status` | `updated` or `up_to_date`. |
|
||||
| `stdout` | Installer stdout. |
|
||||
| `stderr` | Installer stderr. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use `--force` only when the user asks to reinstall or when verifying release assets.
|
||||
@@ -0,0 +1,34 @@
|
||||
# `openstock version`
|
||||
|
||||
## Purpose
|
||||
|
||||
Return the installed `openstock` package name and version.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
openstock version
|
||||
```
|
||||
|
||||
## Input
|
||||
|
||||
No arguments.
|
||||
|
||||
## IO
|
||||
|
||||
| Direction | Data |
|
||||
| --- | --- |
|
||||
| External IO | none |
|
||||
| File IO | none |
|
||||
| Side effect | none |
|
||||
|
||||
## Output Fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `name` | Cargo package/program name. |
|
||||
| `version` | Version of the running `openstock` binary. |
|
||||
|
||||
## Agent Notes
|
||||
|
||||
Use this before update checks or when reporting runtime provenance.
|
||||
@@ -4,6 +4,7 @@ pub mod cache;
|
||||
pub mod dart;
|
||||
pub mod market;
|
||||
pub mod order;
|
||||
pub mod score;
|
||||
pub mod search;
|
||||
pub mod universe;
|
||||
pub mod update;
|
||||
@@ -15,6 +16,7 @@ pub use cache::handle_cache;
|
||||
pub use dart::handle_dart;
|
||||
pub use market::handle_market;
|
||||
pub use order::handle_order;
|
||||
pub use score::handle_score;
|
||||
pub use search::handle_search;
|
||||
pub use universe::handle_universe;
|
||||
pub use update::handle_update;
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ScoreCommands {
|
||||
/// 종목 평가 점수 저장 또는 갱신
|
||||
Set(ScoreSetCommand),
|
||||
|
||||
/// 종목 평가 점수 조회
|
||||
Get(ScoreSymbolCommand),
|
||||
|
||||
/// 저장된 종목 평가 점수 목록 조회
|
||||
List,
|
||||
|
||||
/// 종목 평가 점수 삭제
|
||||
Delete(ScoreSymbolCommand),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct ScoreSetCommand {
|
||||
/// 종목코드 또는 종목 ID
|
||||
pub symbol: String,
|
||||
|
||||
/// 종목 평가 점수 (0~100)
|
||||
pub score: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct ScoreSymbolCommand {
|
||||
/// 종목코드 또는 종목 ID
|
||||
pub symbol: String,
|
||||
}
|
||||
|
||||
pub fn handle_score(sub: &ScoreCommands) {
|
||||
match sub {
|
||||
ScoreCommands::Set(command) => {
|
||||
match crate::core::scores::set(&command.symbol, command.score) {
|
||||
Ok(record) => print_record("score set", "종목 평가 점수 저장 결과", record),
|
||||
Err(err) => eprintln!(
|
||||
"{}",
|
||||
crate::core::output::error("score set", "종목 평가 점수 저장 실패", &err)
|
||||
),
|
||||
}
|
||||
}
|
||||
ScoreCommands::Get(command) => match crate::core::scores::get(&command.symbol) {
|
||||
Ok(Some(record)) => print_record("score get", "종목 평가 점수 조회 결과", record),
|
||||
Ok(None) => eprintln!(
|
||||
"{}",
|
||||
crate::core::output::error(
|
||||
"score get",
|
||||
"종목 평가 점수 조회 실패",
|
||||
"해당 종목의 저장된 점수가 없습니다.",
|
||||
)
|
||||
),
|
||||
Err(err) => eprintln!(
|
||||
"{}",
|
||||
crate::core::output::error("score get", "종목 평가 점수 조회 실패", &err)
|
||||
),
|
||||
},
|
||||
ScoreCommands::List => match crate::core::scores::list() {
|
||||
Ok(scores) => println!(
|
||||
"{}",
|
||||
crate::core::output::explained_with_raw(
|
||||
"score list",
|
||||
"저장된 종목 평가 점수 목록",
|
||||
vec![
|
||||
crate::core::output::field(
|
||||
"path",
|
||||
"종목 평가 점수를 저장하는 파일 경로",
|
||||
serde_json::json!(crate::core::scores::path()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"count",
|
||||
"저장된 종목 평가 점수 개수",
|
||||
serde_json::json!(scores.len()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"scores",
|
||||
"점수 내림차순으로 정렬한 종목 평가 목록",
|
||||
serde_json::json!(scores),
|
||||
),
|
||||
],
|
||||
serde_json::Value::Null,
|
||||
)
|
||||
),
|
||||
Err(err) => eprintln!(
|
||||
"{}",
|
||||
crate::core::output::error("score list", "종목 평가 점수 목록 조회 실패", &err)
|
||||
),
|
||||
},
|
||||
ScoreCommands::Delete(command) => match crate::core::scores::delete(&command.symbol) {
|
||||
Ok(removed) => println!(
|
||||
"{}",
|
||||
crate::core::output::explained_with_raw(
|
||||
"score delete",
|
||||
"종목 평가 점수 삭제 결과",
|
||||
vec![
|
||||
crate::core::output::field(
|
||||
"path",
|
||||
"종목 평가 점수를 저장하는 파일 경로",
|
||||
serde_json::json!(crate::core::scores::path()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"symbol",
|
||||
"삭제 요청한 종목코드 또는 종목 ID",
|
||||
serde_json::json!(command.symbol.trim().to_ascii_uppercase()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"deleted",
|
||||
"저장된 점수가 존재해서 삭제되었는지 여부",
|
||||
serde_json::json!(removed.is_some()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"removed",
|
||||
"삭제된 기존 점수 기록",
|
||||
serde_json::json!(removed),
|
||||
),
|
||||
],
|
||||
serde_json::Value::Null,
|
||||
)
|
||||
),
|
||||
Err(err) => eprintln!(
|
||||
"{}",
|
||||
crate::core::output::error("score delete", "종목 평가 점수 삭제 실패", &err)
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn print_record(command: &str, description: &str, record: crate::core::scores::StockScore) {
|
||||
println!(
|
||||
"{}",
|
||||
crate::core::output::explained_with_raw(
|
||||
command,
|
||||
description,
|
||||
vec![
|
||||
crate::core::output::field(
|
||||
"path",
|
||||
"종목 평가 점수를 저장하는 파일 경로",
|
||||
serde_json::json!(crate::core::scores::path()),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"symbol",
|
||||
"점수를 매긴 종목코드 또는 종목 ID",
|
||||
serde_json::json!(record.symbol),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"score",
|
||||
"종목 평가 점수. 0은 최저, 100은 최고",
|
||||
serde_json::json!(record.score),
|
||||
),
|
||||
crate::core::output::field(
|
||||
"updated_at_unix",
|
||||
"점수를 저장하거나 갱신한 Unix timestamp(초)",
|
||||
serde_json::json!(record.updated_at_unix),
|
||||
),
|
||||
],
|
||||
serde_json::Value::Null,
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ pub mod http;
|
||||
pub mod output;
|
||||
pub mod paths;
|
||||
pub mod registry;
|
||||
pub mod scores;
|
||||
pub mod stock;
|
||||
pub mod trader;
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ pub fn env_file() -> PathBuf {
|
||||
config_dir().join(".env")
|
||||
}
|
||||
|
||||
pub fn score_file() -> PathBuf {
|
||||
config_dir().join("scores.json")
|
||||
}
|
||||
|
||||
pub fn cache_dir() -> PathBuf {
|
||||
config_dir().join("cache")
|
||||
}
|
||||
@@ -49,4 +53,10 @@ mod tests {
|
||||
let path = cache_namespace("universe/kind");
|
||||
assert!(path.ends_with("cache/universe/kind"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn score_file_lives_under_config_dir() {
|
||||
let path = score_file();
|
||||
assert!(path.ends_with("scores.json"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StockScoreStore {
|
||||
pub version: u32,
|
||||
pub scores: BTreeMap<String, StockScore>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StockScore {
|
||||
pub symbol: String,
|
||||
pub score: u8,
|
||||
pub updated_at_unix: u64,
|
||||
}
|
||||
|
||||
impl Default for StockScoreStore {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: 1,
|
||||
scores: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(symbol: &str, score: u16) -> Result<StockScore, String> {
|
||||
validate_score(score)?;
|
||||
let symbol = normalize_symbol(symbol)?;
|
||||
let mut store = load()?;
|
||||
let record = StockScore {
|
||||
symbol: symbol.clone(),
|
||||
score: score as u8,
|
||||
updated_at_unix: current_unix_timestamp(),
|
||||
};
|
||||
store.scores.insert(symbol, record.clone());
|
||||
save(&store)?;
|
||||
Ok(record)
|
||||
}
|
||||
|
||||
pub fn get(symbol: &str) -> Result<Option<StockScore>, String> {
|
||||
let symbol = normalize_symbol(symbol)?;
|
||||
Ok(load()?.scores.get(&symbol).cloned())
|
||||
}
|
||||
|
||||
pub fn list() -> Result<Vec<StockScore>, String> {
|
||||
let mut scores = load()?.scores.into_values().collect::<Vec<_>>();
|
||||
scores.sort_by(|a, b| b.score.cmp(&a.score).then_with(|| a.symbol.cmp(&b.symbol)));
|
||||
Ok(scores)
|
||||
}
|
||||
|
||||
pub fn delete(symbol: &str) -> Result<Option<StockScore>, String> {
|
||||
let symbol = normalize_symbol(symbol)?;
|
||||
let mut store = load()?;
|
||||
let removed = store.scores.remove(&symbol);
|
||||
if removed.is_some() {
|
||||
save(&store)?;
|
||||
}
|
||||
Ok(removed)
|
||||
}
|
||||
|
||||
pub fn path() -> std::path::PathBuf {
|
||||
crate::core::paths::score_file()
|
||||
}
|
||||
|
||||
fn load() -> Result<StockScoreStore, String> {
|
||||
let path = path();
|
||||
if !path.exists() {
|
||||
return Ok(StockScoreStore::default());
|
||||
}
|
||||
let text = fs::read_to_string(&path)
|
||||
.map_err(|err| format!("종목 점수 파일 읽기 실패 ({}): {}", path.display(), err))?;
|
||||
serde_json::from_str(&text).map_err(|err| {
|
||||
format!(
|
||||
"종목 점수 파일 JSON 파싱 실패 ({}): {}",
|
||||
path.display(),
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn save(store: &StockScoreStore) -> Result<(), String> {
|
||||
let path = path();
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)
|
||||
.map_err(|err| format!("설정 디렉터리 생성 실패 ({}): {}", parent.display(), err))?;
|
||||
}
|
||||
let text = serde_json::to_string_pretty(store)
|
||||
.map_err(|err| format!("종목 점수 JSON 직렬화 실패: {}", err))?;
|
||||
write_atomic(&path, &text)
|
||||
}
|
||||
|
||||
fn write_atomic(path: &Path, text: &str) -> Result<(), String> {
|
||||
let tmp_path = path.with_extension("json.tmp");
|
||||
fs::write(&tmp_path, text).map_err(|err| {
|
||||
format!(
|
||||
"종목 점수 임시 파일 쓰기 실패 ({}): {}",
|
||||
tmp_path.display(),
|
||||
err
|
||||
)
|
||||
})?;
|
||||
fs::rename(&tmp_path, path).map_err(|err| {
|
||||
format!(
|
||||
"종목 점수 파일 교체 실패 ({} -> {}): {}",
|
||||
tmp_path.display(),
|
||||
path.display(),
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn normalize_symbol(symbol: &str) -> Result<String, String> {
|
||||
let symbol = symbol.trim().to_ascii_uppercase();
|
||||
crate::core::stock::validate_symbol(&symbol)?;
|
||||
Ok(symbol)
|
||||
}
|
||||
|
||||
fn validate_score(score: u16) -> Result<(), String> {
|
||||
if score <= 100 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("종목 점수는 0 이상 100 이하이어야 합니다.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn current_unix_timestamp() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|duration| duration.as_secs())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn normalizes_symbol_to_uppercase() {
|
||||
assert_eq!(normalize_symbol(" a123 ").unwrap(), "A123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_score_bounds() {
|
||||
assert!(validate_score(0).is_ok());
|
||||
assert!(validate_score(100).is_ok());
|
||||
assert!(validate_score(101).is_err());
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use commands::cache::CacheCommands;
|
||||
use commands::dart::DartCommands;
|
||||
use commands::market::MarketCommand;
|
||||
use commands::order::OrderCommands;
|
||||
use commands::score::ScoreCommands;
|
||||
use commands::universe::UniverseCommands;
|
||||
|
||||
mod apis;
|
||||
@@ -74,6 +75,12 @@ enum Commands {
|
||||
query: String,
|
||||
},
|
||||
|
||||
/// 종목 평가 점수 저장 및 조회
|
||||
Score {
|
||||
#[command(subcommand)]
|
||||
sub: ScoreCommands,
|
||||
},
|
||||
|
||||
/// 종목 정보 및 기업정보 조회
|
||||
Market(MarketCommand),
|
||||
}
|
||||
@@ -91,6 +98,7 @@ fn main() {
|
||||
Some(Commands::Order { sub }) => commands::handle_order(sub),
|
||||
Some(Commands::Universe { sub }) => commands::handle_universe(sub),
|
||||
Some(Commands::Search { query }) => commands::handle_search(query),
|
||||
Some(Commands::Score { sub }) => commands::handle_score(sub),
|
||||
Some(Commands::Market(command)) => commands::handle_market(command),
|
||||
None => {
|
||||
println!(
|
||||
|
||||
Reference in New Issue
Block a user