kwcli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kiwoom/__init__.py +47 -0
- kiwoom/_data/kiwoom_api_spec.json +66372 -0
- kiwoom/core/__init__.py +6 -0
- kiwoom/core/auth.py +349 -0
- kiwoom/core/client.py +244 -0
- kiwoom/core/errors.py +177 -0
- kiwoom/core/platform_paths.py +68 -0
- kiwoom/core/profiles.py +143 -0
- kiwoom/core/runtime.py +153 -0
- kiwoom/core/secrets.py +217 -0
- kiwoom/core/settings.py +64 -0
- kiwoom/core/token_store.py +186 -0
- kiwoom/core/types.py +28 -0
- kiwoom/core/ws_client.py +262 -0
- kiwoom/realtime/__init__.py +30 -0
- kiwoom/realtime/decoders.py +171 -0
- kiwoom/realtime/events.py +98 -0
- kiwoom/realtime/packets.py +65 -0
- kiwoom/realtime/schemas.py +76 -0
- kiwoom/realtime/stream.py +213 -0
- kiwoom/specs.py +272 -0
- kiwoom_cli/README.md +671 -0
- kiwoom_cli/__init__.py +9 -0
- kiwoom_cli/__main__.py +5 -0
- kiwoom_cli/argument_maps.py +561 -0
- kiwoom_cli/arguments.py +147 -0
- kiwoom_cli/auth_context.py +64 -0
- kiwoom_cli/banner.py +125 -0
- kiwoom_cli/commands/__init__.py +1 -0
- kiwoom_cli/commands/auth.py +406 -0
- kiwoom_cli/commands/groups.py +281 -0
- kiwoom_cli/commands/mapped.py +74 -0
- kiwoom_cli/commands/orders.py +158 -0
- kiwoom_cli/commands/spec.py +98 -0
- kiwoom_cli/commands/stocks.py +100 -0
- kiwoom_cli/commands/streams.py +470 -0
- kiwoom_cli/doctor.py +324 -0
- kiwoom_cli/errors.py +24 -0
- kiwoom_cli/executor/__init__.py +33 -0
- kiwoom_cli/executor/condition.py +374 -0
- kiwoom_cli/executor/rest.py +132 -0
- kiwoom_cli/executor/waits.py +34 -0
- kiwoom_cli/executor/websocket.py +131 -0
- kiwoom_cli/main.py +203 -0
- kiwoom_cli/maps/README.md +99 -0
- kiwoom_cli/maps/api_commands.csv +209 -0
- kiwoom_cli/maps/arguments.csv +731 -0
- kiwoom_cli/maps/order_confirmation_commands.csv +13 -0
- kiwoom_cli/maps/order_confirmation_fields.csv +71 -0
- kiwoom_cli/maps/order_price_policies.csv +47 -0
- kiwoom_cli/maps/order_value_labels.csv +28 -0
- kiwoom_cli/maps/positional_arguments.csv +21 -0
- kiwoom_cli/order_confirmation.py +167 -0
- kiwoom_cli/output.py +136 -0
- kiwoom_cli/registry.py +95 -0
- kiwoom_cli/safety.py +30 -0
- kiwoom_cli/setup.py +533 -0
- kwcli-0.1.0.dist-info/METADATA +215 -0
- kwcli-0.1.0.dist-info/RECORD +62 -0
- kwcli-0.1.0.dist-info/WHEEL +4 -0
- kwcli-0.1.0.dist-info/entry_points.txt +2 -0
- kwcli-0.1.0.dist-info/licenses/LICENSE.md +36 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
command_path,kind,message
|
|
2
|
+
kiwoomcli domestic orders buy,주식 매수,주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
3
|
+
kiwoomcli domestic orders sell,주식 매도,주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
4
|
+
kiwoomcli domestic orders modify,주식 정정,정정주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
5
|
+
kiwoomcli domestic orders cancel,주식 취소,취소주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
6
|
+
kiwoomcli domestic orders credit-buy,신용 매수,주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
7
|
+
kiwoomcli domestic orders credit-sell,신용 매도,주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
8
|
+
kiwoomcli domestic orders credit-modify,신용 정정,정정주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
9
|
+
kiwoomcli domestic orders credit-cancel,신용 취소,취소주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
10
|
+
kiwoomcli domestic orders gold-buy,금현물 매수,금현물 주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
11
|
+
kiwoomcli domestic orders gold-sell,금현물 매도,금현물 주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
12
|
+
kiwoomcli domestic orders gold-modify,금현물 정정,금현물 정정주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
13
|
+
kiwoomcli domestic orders gold-cancel,금현물 취소,금현물 취소주문은 아직 전송되지 않았습니다. 실제 전송하려면 같은 명령에 --confirm을 붙여 다시 실행하세요.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
command_path,output_key,label,arg_name,value_label_group,include_if_empty,empty_display
|
|
2
|
+
kiwoomcli domestic orders buy,kind,구분,__kind__,,Y,
|
|
3
|
+
kiwoomcli domestic orders buy,exchange,시장,exchange,,Y,
|
|
4
|
+
kiwoomcli domestic orders buy,code,종목,code,,Y,
|
|
5
|
+
kiwoomcli domestic orders buy,quantity,수량,qty,,Y,
|
|
6
|
+
kiwoomcli domestic orders buy,order_type,유형,order_type,order_type,Y,
|
|
7
|
+
kiwoomcli domestic orders buy,price,가격,price,,Y,없음
|
|
8
|
+
kiwoomcli domestic orders sell,kind,구분,__kind__,,Y,
|
|
9
|
+
kiwoomcli domestic orders sell,exchange,시장,exchange,,Y,
|
|
10
|
+
kiwoomcli domestic orders sell,code,종목,code,,Y,
|
|
11
|
+
kiwoomcli domestic orders sell,quantity,수량,qty,,Y,
|
|
12
|
+
kiwoomcli domestic orders sell,order_type,유형,order_type,order_type,Y,
|
|
13
|
+
kiwoomcli domestic orders sell,price,가격,price,,Y,없음
|
|
14
|
+
kiwoomcli domestic orders modify,kind,구분,__kind__,,Y,
|
|
15
|
+
kiwoomcli domestic orders modify,exchange,시장,exchange,,Y,
|
|
16
|
+
kiwoomcli domestic orders modify,code,종목,code,,Y,
|
|
17
|
+
kiwoomcli domestic orders modify,original_order_id,원주문번호,order_id,,Y,
|
|
18
|
+
kiwoomcli domestic orders modify,quantity,정정수량,qty,,Y,
|
|
19
|
+
kiwoomcli domestic orders modify,price,정정가격,price,,Y,
|
|
20
|
+
kiwoomcli domestic orders cancel,kind,구분,__kind__,,Y,
|
|
21
|
+
kiwoomcli domestic orders cancel,exchange,시장,exchange,,Y,
|
|
22
|
+
kiwoomcli domestic orders cancel,code,종목,code,,Y,
|
|
23
|
+
kiwoomcli domestic orders cancel,original_order_id,원주문번호,order_id,,Y,
|
|
24
|
+
kiwoomcli domestic orders cancel,quantity,취소수량,qty,,Y,
|
|
25
|
+
kiwoomcli domestic orders credit-buy,kind,구분,__kind__,,Y,
|
|
26
|
+
kiwoomcli domestic orders credit-buy,exchange,시장,exchange,,Y,
|
|
27
|
+
kiwoomcli domestic orders credit-buy,code,종목,code,,Y,
|
|
28
|
+
kiwoomcli domestic orders credit-buy,quantity,수량,qty,,Y,
|
|
29
|
+
kiwoomcli domestic orders credit-buy,order_type,유형,order_type,order_type,Y,
|
|
30
|
+
kiwoomcli domestic orders credit-buy,price,가격,price,,Y,없음
|
|
31
|
+
kiwoomcli domestic orders credit-buy,condition_price,조건가격,condition_price,,N,
|
|
32
|
+
kiwoomcli domestic orders credit-sell,kind,구분,__kind__,,Y,
|
|
33
|
+
kiwoomcli domestic orders credit-sell,exchange,시장,exchange,,Y,
|
|
34
|
+
kiwoomcli domestic orders credit-sell,code,종목,code,,Y,
|
|
35
|
+
kiwoomcli domestic orders credit-sell,quantity,수량,qty,,Y,
|
|
36
|
+
kiwoomcli domestic orders credit-sell,order_type,유형,order_type,order_type,Y,
|
|
37
|
+
kiwoomcli domestic orders credit-sell,price,가격,price,,Y,없음
|
|
38
|
+
kiwoomcli domestic orders credit-sell,credit_deal,신용거래,credit_deal,credit_deal,Y,
|
|
39
|
+
kiwoomcli domestic orders credit-sell,loan_date,대출일,loan_date,,N,
|
|
40
|
+
kiwoomcli domestic orders credit-sell,condition_price,조건가격,condition_price,,N,
|
|
41
|
+
kiwoomcli domestic orders credit-modify,kind,구분,__kind__,,Y,
|
|
42
|
+
kiwoomcli domestic orders credit-modify,exchange,시장,exchange,,Y,
|
|
43
|
+
kiwoomcli domestic orders credit-modify,code,종목,code,,Y,
|
|
44
|
+
kiwoomcli domestic orders credit-modify,original_order_id,원주문번호,order_id,,Y,
|
|
45
|
+
kiwoomcli domestic orders credit-modify,quantity,정정수량,qty,,Y,
|
|
46
|
+
kiwoomcli domestic orders credit-modify,price,정정가격,price,,Y,
|
|
47
|
+
kiwoomcli domestic orders credit-modify,condition_price,정정조건가격,condition_price,,N,
|
|
48
|
+
kiwoomcli domestic orders credit-cancel,kind,구분,__kind__,,Y,
|
|
49
|
+
kiwoomcli domestic orders credit-cancel,exchange,시장,exchange,,Y,
|
|
50
|
+
kiwoomcli domestic orders credit-cancel,code,종목,code,,Y,
|
|
51
|
+
kiwoomcli domestic orders credit-cancel,original_order_id,원주문번호,order_id,,Y,
|
|
52
|
+
kiwoomcli domestic orders credit-cancel,quantity,취소수량,qty,,Y,
|
|
53
|
+
kiwoomcli domestic orders gold-buy,kind,구분,__kind__,,Y,
|
|
54
|
+
kiwoomcli domestic orders gold-buy,code,종목,code,,Y,
|
|
55
|
+
kiwoomcli domestic orders gold-buy,quantity,수량,qty,,Y,
|
|
56
|
+
kiwoomcli domestic orders gold-buy,order_type,유형,order_type,order_type,Y,
|
|
57
|
+
kiwoomcli domestic orders gold-buy,price,가격,price,,Y,
|
|
58
|
+
kiwoomcli domestic orders gold-sell,kind,구분,__kind__,,Y,
|
|
59
|
+
kiwoomcli domestic orders gold-sell,code,종목,code,,Y,
|
|
60
|
+
kiwoomcli domestic orders gold-sell,quantity,수량,qty,,Y,
|
|
61
|
+
kiwoomcli domestic orders gold-sell,order_type,유형,order_type,order_type,Y,
|
|
62
|
+
kiwoomcli domestic orders gold-sell,price,가격,price,,Y,
|
|
63
|
+
kiwoomcli domestic orders gold-modify,kind,구분,__kind__,,Y,
|
|
64
|
+
kiwoomcli domestic orders gold-modify,code,종목,code,,Y,
|
|
65
|
+
kiwoomcli domestic orders gold-modify,original_order_id,원주문번호,order_id,,Y,
|
|
66
|
+
kiwoomcli domestic orders gold-modify,quantity,정정수량,qty,,Y,
|
|
67
|
+
kiwoomcli domestic orders gold-modify,price,정정가격,price,,Y,
|
|
68
|
+
kiwoomcli domestic orders gold-cancel,kind,구분,__kind__,,Y,
|
|
69
|
+
kiwoomcli domestic orders gold-cancel,original_order_id,원주문번호,order_id,,Y,
|
|
70
|
+
kiwoomcli domestic orders gold-cancel,code,종목,code,,Y,
|
|
71
|
+
kiwoomcli domestic orders gold-cancel,quantity,취소수량,qty,,Y,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
command_path,order_type,price_option,price_policy,condition_price_option,condition_price_policy,description
|
|
2
|
+
kiwoomcli domestic orders buy,limit,--price,required,,,지정가 매수는 주문단가가 필요합니다.
|
|
3
|
+
kiwoomcli domestic orders buy,market,--price,forbidden,,,시장가 매수는 주문단가를 보내지 않습니다.
|
|
4
|
+
kiwoomcli domestic orders sell,limit,--price,required,,,지정가 매도는 주문단가가 필요합니다.
|
|
5
|
+
kiwoomcli domestic orders sell,market,--price,forbidden,,,시장가 매도는 주문단가를 보내지 않습니다.
|
|
6
|
+
kiwoomcli domestic orders credit-buy,limit,--price,required,,,지정가 신용매수는 주문단가가 필요합니다.
|
|
7
|
+
kiwoomcli domestic orders credit-buy,market,--price,forbidden,,,시장가 신용매수는 주문단가를 보내지 않습니다.
|
|
8
|
+
kiwoomcli domestic orders credit-buy,conditional-limit,--price,required,,,조건부지정가는 주문단가가 필요합니다.
|
|
9
|
+
kiwoomcli domestic orders credit-buy,after-hours-close,--price,forbidden,,,장마감후시간외는 별도 주문단가를 보내지 않습니다.
|
|
10
|
+
kiwoomcli domestic orders credit-buy,pre-open,--price,forbidden,,,장시작전시간외는 별도 주문단가를 보내지 않습니다.
|
|
11
|
+
kiwoomcli domestic orders credit-buy,after-hours-single,--price,required,,,시간외단일가는 주문단가가 필요합니다.
|
|
12
|
+
kiwoomcli domestic orders credit-buy,best-limit,--price,forbidden,,,최유리지정가는 주문단가를 보내지 않습니다.
|
|
13
|
+
kiwoomcli domestic orders credit-buy,top-priority,--price,forbidden,,,최우선지정가는 주문단가를 보내지 않습니다.
|
|
14
|
+
kiwoomcli domestic orders credit-buy,limit-ioc,--price,required,,,보통 IOC는 주문단가가 필요합니다.
|
|
15
|
+
kiwoomcli domestic orders credit-buy,market-ioc,--price,forbidden,,,시장가 IOC는 주문단가를 보내지 않습니다.
|
|
16
|
+
kiwoomcli domestic orders credit-buy,best-ioc,--price,forbidden,,,최유리 IOC는 주문단가를 보내지 않습니다.
|
|
17
|
+
kiwoomcli domestic orders credit-buy,limit-fok,--price,required,,,보통 FOK는 주문단가가 필요합니다.
|
|
18
|
+
kiwoomcli domestic orders credit-buy,market-fok,--price,forbidden,,,시장가 FOK는 주문단가를 보내지 않습니다.
|
|
19
|
+
kiwoomcli domestic orders credit-buy,best-fok,--price,forbidden,,,최유리 FOK는 주문단가를 보내지 않습니다.
|
|
20
|
+
kiwoomcli domestic orders credit-buy,stop-limit,--price,required,--condition-price,required,스톱지정가는 주문단가와 조건단가가 필요합니다.
|
|
21
|
+
kiwoomcli domestic orders credit-buy,mid,--price,forbidden,,,중간가는 주문단가를 보내지 않습니다.
|
|
22
|
+
kiwoomcli domestic orders credit-buy,mid-ioc,--price,forbidden,,,중간가 IOC는 주문단가를 보내지 않습니다.
|
|
23
|
+
kiwoomcli domestic orders credit-buy,mid-fok,--price,forbidden,,,중간가 FOK는 주문단가를 보내지 않습니다.
|
|
24
|
+
kiwoomcli domestic orders credit-sell,limit,--price,required,,,지정가 신용매도는 주문단가가 필요합니다.
|
|
25
|
+
kiwoomcli domestic orders credit-sell,market,--price,forbidden,,,시장가 신용매도는 주문단가를 보내지 않습니다.
|
|
26
|
+
kiwoomcli domestic orders credit-sell,conditional-limit,--price,required,,,조건부지정가는 주문단가가 필요합니다.
|
|
27
|
+
kiwoomcli domestic orders credit-sell,after-hours-close,--price,forbidden,,,장마감후시간외는 별도 주문단가를 보내지 않습니다.
|
|
28
|
+
kiwoomcli domestic orders credit-sell,pre-open,--price,forbidden,,,장시작전시간외는 별도 주문단가를 보내지 않습니다.
|
|
29
|
+
kiwoomcli domestic orders credit-sell,after-hours-single,--price,required,,,시간외단일가는 주문단가가 필요합니다.
|
|
30
|
+
kiwoomcli domestic orders credit-sell,best-limit,--price,forbidden,,,최유리지정가는 주문단가를 보내지 않습니다.
|
|
31
|
+
kiwoomcli domestic orders credit-sell,top-priority,--price,forbidden,,,최우선지정가는 주문단가를 보내지 않습니다.
|
|
32
|
+
kiwoomcli domestic orders credit-sell,limit-ioc,--price,required,,,보통 IOC는 주문단가가 필요합니다.
|
|
33
|
+
kiwoomcli domestic orders credit-sell,market-ioc,--price,forbidden,,,시장가 IOC는 주문단가를 보내지 않습니다.
|
|
34
|
+
kiwoomcli domestic orders credit-sell,best-ioc,--price,forbidden,,,최유리 IOC는 주문단가를 보내지 않습니다.
|
|
35
|
+
kiwoomcli domestic orders credit-sell,limit-fok,--price,required,,,보통 FOK는 주문단가가 필요합니다.
|
|
36
|
+
kiwoomcli domestic orders credit-sell,market-fok,--price,forbidden,,,시장가 FOK는 주문단가를 보내지 않습니다.
|
|
37
|
+
kiwoomcli domestic orders credit-sell,best-fok,--price,forbidden,,,최유리 FOK는 주문단가를 보내지 않습니다.
|
|
38
|
+
kiwoomcli domestic orders credit-sell,stop-limit,--price,required,--condition-price,required,스톱지정가는 주문단가와 조건단가가 필요합니다.
|
|
39
|
+
kiwoomcli domestic orders credit-sell,mid,--price,forbidden,,,중간가는 주문단가를 보내지 않습니다.
|
|
40
|
+
kiwoomcli domestic orders credit-sell,mid-ioc,--price,forbidden,,,중간가 IOC는 주문단가를 보내지 않습니다.
|
|
41
|
+
kiwoomcli domestic orders credit-sell,mid-fok,--price,forbidden,,,중간가 FOK는 주문단가를 보내지 않습니다.
|
|
42
|
+
kiwoomcli domestic orders gold-buy,limit,--price,required,,,금현물 지정가 매수는 주문단가가 필요합니다.
|
|
43
|
+
kiwoomcli domestic orders gold-buy,limit-ioc,--price,required,,,금현물 IOC 매수는 주문단가가 필요합니다.
|
|
44
|
+
kiwoomcli domestic orders gold-buy,limit-fok,--price,required,,,금현물 FOK 매수는 주문단가가 필요합니다.
|
|
45
|
+
kiwoomcli domestic orders gold-sell,limit,--price,required,,,금현물 지정가 매도는 주문단가가 필요합니다.
|
|
46
|
+
kiwoomcli domestic orders gold-sell,limit-ioc,--price,required,,,금현물 IOC 매도는 주문단가가 필요합니다.
|
|
47
|
+
kiwoomcli domestic orders gold-sell,limit-fok,--price,required,,,금현물 FOK 매도는 주문단가가 필요합니다.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
group,value,label
|
|
2
|
+
order_type,limit,지정가
|
|
3
|
+
order_type,market,시장가
|
|
4
|
+
order_type,conditional-limit,조건부지정가
|
|
5
|
+
order_type,after-hours-close,장마감후시간외
|
|
6
|
+
order_type,pre-open,장시작전시간외
|
|
7
|
+
order_type,after-hours-single,시간외단일가
|
|
8
|
+
order_type,best-limit,최유리지정가
|
|
9
|
+
order_type,top-priority,최우선지정가
|
|
10
|
+
order_type,limit-ioc,보통(IOC)
|
|
11
|
+
order_type,market-ioc,시장가(IOC)
|
|
12
|
+
order_type,best-ioc,최유리(IOC)
|
|
13
|
+
order_type,limit-fok,보통(FOK)
|
|
14
|
+
order_type,market-fok,시장가(FOK)
|
|
15
|
+
order_type,best-fok,최유리(FOK)
|
|
16
|
+
order_type,stop-limit,스톱지정가
|
|
17
|
+
order_type,mid,중간가
|
|
18
|
+
order_type,mid-ioc,중간가(IOC)
|
|
19
|
+
order_type,mid-fok,중간가(FOK)
|
|
20
|
+
credit_deal,financing,융자
|
|
21
|
+
credit_deal,financing-all,융자합
|
|
22
|
+
order_type,vwap-limit,VWAP지정가
|
|
23
|
+
order_type,twap-limit,TWAP지정가
|
|
24
|
+
order_type,loc,LOC
|
|
25
|
+
order_type,moc,MOC
|
|
26
|
+
order_type,vwap-market,VWAP시장가
|
|
27
|
+
order_type,twap-market,TWAP시장가
|
|
28
|
+
order_type,stop,STOP
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
command_path,canonical_form,positional_form,position,name,dest,option,status,reason
|
|
2
|
+
kiwoomcli setup,kiwoomcli setup --alias <alias> --mode <mode>,kiwoomcli setup <alias> --mode <mode>,1,alias,alias,--alias,allow,setup/login target alias is the primary operand
|
|
3
|
+
kiwoomcli auth login,kiwoomcli auth login --alias <alias> --mode <mode>,kiwoomcli auth login <alias> --mode <mode>,1,alias,alias,--alias,allow,auth login target alias is the primary operand
|
|
4
|
+
kiwoomcli auth status,kiwoomcli auth status --profile <alias>,kiwoomcli auth status <alias>,1,alias,profile,--profile,allow,profile status naturally targets one alias
|
|
5
|
+
kiwoomcli auth refresh,kiwoomcli auth refresh --profile <alias>,kiwoomcli auth refresh <alias>,1,alias,profile,--profile,allow,profile refresh naturally targets one alias
|
|
6
|
+
kiwoomcli auth revoke,kiwoomcli auth revoke --profile <alias>,kiwoomcli auth revoke <alias>,1,alias,profile,--profile,allow,profile token revoke naturally targets one alias
|
|
7
|
+
kiwoomcli auth clear,kiwoomcli auth clear --profile <alias> --all,kiwoomcli auth clear <alias> --all,1,alias,profile,--profile,allow,profile credential cleanup naturally targets one alias
|
|
8
|
+
kiwoomcli domestic stocks info,kiwoomcli domestic stocks info --code <code>,kiwoomcli domestic stocks info <code>,1,code,code,--code,candidate,common single-stock lookup shorthand
|
|
9
|
+
kiwoomcli domestic quotes price,kiwoomcli domestic quotes price --code <code>,kiwoomcli domestic quotes price <code>,1,code,code,--code,candidate,common single-stock quote shorthand
|
|
10
|
+
kiwoomcli domestic orderbooks list,kiwoomcli domestic orderbooks list --code <code>,kiwoomcli domestic orderbooks list <code>,1,code,code,--code,candidate,common single-stock orderbook shorthand
|
|
11
|
+
kiwoomcli domestic candles daily,kiwoomcli domestic candles daily --code <code>,kiwoomcli domestic candles daily <code>,1,code,code,--code,candidate,common single-stock chart shorthand
|
|
12
|
+
kiwoomcli domestic streams trades,kiwoomcli domestic streams trades --code <code>,kiwoomcli domestic streams trades <code>,1,code,code,--code,candidate,common single-stock realtime shorthand
|
|
13
|
+
kiwoomcli domestic streams conditions-search,kiwoomcli domestic streams conditions-search [--seq <seq>] --exchange <exchange>,defer,1,seq,seq,--seq,defer,seq is optional because the command internally loads saved conditions with CNSRLST
|
|
14
|
+
kiwoomcli domestic streams conditions-subscribe,kiwoomcli domestic streams conditions-subscribe [--seq <seq>] --exchange <exchange>,defer,1,seq,seq,--seq,defer,seq is optional because the command internally loads saved conditions with CNSRLST
|
|
15
|
+
kiwoomcli domestic streams conditions-unsubscribe,kiwoomcli domestic streams conditions-unsubscribe [--seq <seq>],defer,1,seq,seq,--seq,defer,one-shot clear is same-session only; positional shorthand would hide that constraint
|
|
16
|
+
kiwoomcli domestic orders buy,kiwoomcli domestic orders buy --code <code> --qty <qty> --price <price> --order-type <type>,defer,1,code,code,--code,defer,write-like order shorthand is deferred for safety and ambiguity
|
|
17
|
+
kiwoomcli domestic orders sell,kiwoomcli domestic orders sell --code <code> --qty <qty> --price <price> --order-type <type>,defer,1,code,code,--code,defer,write-like order shorthand is deferred for safety and ambiguity
|
|
18
|
+
kiwoomcli domestic orders modify,kiwoomcli domestic orders modify --code <code> --order-id <order-id> --qty <qty> --price <price>,defer,1,code,code,--code,defer,modify shorthand is deferred because order-id qty price order can be confused
|
|
19
|
+
kiwoomcli domestic orders modify,kiwoomcli domestic orders modify --code <code> --order-id <order-id> --qty <qty> --price <price>,defer,2,order-id,order_id,--order-id,defer,modify shorthand is deferred because order-id qty price order can be confused
|
|
20
|
+
kiwoomcli domestic orders cancel,kiwoomcli domestic orders cancel --code <code> --order-id <order-id> --qty <qty>,defer,1,code,code,--code,defer,cancel shorthand is deferred because order-id and quantity mistakes are high impact
|
|
21
|
+
kiwoomcli domestic orders cancel,kiwoomcli domestic orders cancel --code <code> --order-id <order-id> --qty <qty>,defer,2,order-id,order_id,--order-id,defer,cancel shorthand is deferred because order-id and quantity mistakes are high impact
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Order confirmation output for confirm-gated domestic order commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import csv
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from kiwoom_cli.errors import CliInternalError
|
|
12
|
+
from kiwoom_cli.output import format_payload
|
|
13
|
+
from kiwoom_cli.registry import CommandDefinition
|
|
14
|
+
|
|
15
|
+
MAP_ROOT = Path(__file__).resolve().parent / "maps"
|
|
16
|
+
COMMANDS_PATH = MAP_ROOT / "order_confirmation_commands.csv"
|
|
17
|
+
FIELDS_PATH = MAP_ROOT / "order_confirmation_fields.csv"
|
|
18
|
+
VALUE_LABELS_PATH = MAP_ROOT / "order_value_labels.csv"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class OrderConfirmationCommand:
|
|
23
|
+
command_path: str
|
|
24
|
+
kind: str
|
|
25
|
+
message: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class OrderConfirmationField:
|
|
30
|
+
command_path: str
|
|
31
|
+
output_key: str
|
|
32
|
+
label: str
|
|
33
|
+
arg_name: str
|
|
34
|
+
value_label_group: str
|
|
35
|
+
include_if_empty: bool
|
|
36
|
+
empty_display: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_order_confirmation(
|
|
40
|
+
definition: CommandDefinition,
|
|
41
|
+
args: argparse.Namespace,
|
|
42
|
+
) -> dict[str, Any]:
|
|
43
|
+
command = get_order_confirmation_command(definition.command_path)
|
|
44
|
+
if command is None:
|
|
45
|
+
raise CliInternalError(
|
|
46
|
+
f"{definition.command_path}: 주문 확인 출력 매핑이 없습니다."
|
|
47
|
+
)
|
|
48
|
+
fields = get_order_confirmation_fields(definition.command_path)
|
|
49
|
+
value_labels = load_value_labels()
|
|
50
|
+
order: dict[str, str] = {}
|
|
51
|
+
display_rows: list[dict[str, str]] = []
|
|
52
|
+
for field in fields:
|
|
53
|
+
value = _field_value(
|
|
54
|
+
field, command=command, args=args, value_labels=value_labels
|
|
55
|
+
)
|
|
56
|
+
if value == "" and not field.include_if_empty:
|
|
57
|
+
continue
|
|
58
|
+
display_value = field.empty_display if value == "" else value
|
|
59
|
+
order[field.output_key] = display_value
|
|
60
|
+
display_rows.append(
|
|
61
|
+
{
|
|
62
|
+
"key": field.output_key,
|
|
63
|
+
"label": field.label,
|
|
64
|
+
"value": display_value,
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
return {
|
|
68
|
+
"message": command.message,
|
|
69
|
+
"order": order,
|
|
70
|
+
"_display_rows": display_rows,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def format_order_confirmation(payload: dict[str, Any], *, output_format: str) -> str:
|
|
75
|
+
if output_format == "pretty":
|
|
76
|
+
return _format_order_confirmation_pretty(payload)
|
|
77
|
+
machine_payload = {
|
|
78
|
+
"message": payload["message"],
|
|
79
|
+
"order": payload["order"],
|
|
80
|
+
}
|
|
81
|
+
return format_payload(machine_payload, output_format=output_format)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def load_order_confirmation_commands(
|
|
85
|
+
map_path: Path | None = None,
|
|
86
|
+
) -> list[OrderConfirmationCommand]:
|
|
87
|
+
resolved_path = map_path or COMMANDS_PATH
|
|
88
|
+
with resolved_path.open(encoding="utf-8", newline="") as file:
|
|
89
|
+
return [
|
|
90
|
+
OrderConfirmationCommand(
|
|
91
|
+
command_path=row["command_path"],
|
|
92
|
+
kind=row["kind"],
|
|
93
|
+
message=row["message"],
|
|
94
|
+
)
|
|
95
|
+
for row in csv.DictReader(file)
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_order_confirmation_command(
|
|
100
|
+
command_path: str,
|
|
101
|
+
) -> OrderConfirmationCommand | None:
|
|
102
|
+
for row in load_order_confirmation_commands():
|
|
103
|
+
if row.command_path == command_path:
|
|
104
|
+
return row
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def load_order_confirmation_fields(
|
|
109
|
+
map_path: Path | None = None,
|
|
110
|
+
) -> list[OrderConfirmationField]:
|
|
111
|
+
resolved_path = map_path or FIELDS_PATH
|
|
112
|
+
with resolved_path.open(encoding="utf-8", newline="") as file:
|
|
113
|
+
return [_field_from_row(row) for row in csv.DictReader(file)]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_order_confirmation_fields(command_path: str) -> list[OrderConfirmationField]:
|
|
117
|
+
return [
|
|
118
|
+
field
|
|
119
|
+
for field in load_order_confirmation_fields()
|
|
120
|
+
if field.command_path == command_path
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def load_value_labels(map_path: Path | None = None) -> dict[tuple[str, str], str]:
|
|
125
|
+
resolved_path = map_path or VALUE_LABELS_PATH
|
|
126
|
+
with resolved_path.open(encoding="utf-8", newline="") as file:
|
|
127
|
+
return {
|
|
128
|
+
(row["group"], row["value"]): row["label"] for row in csv.DictReader(file)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _field_from_row(row: dict[str, str]) -> OrderConfirmationField:
|
|
133
|
+
return OrderConfirmationField(
|
|
134
|
+
command_path=row["command_path"],
|
|
135
|
+
output_key=row["output_key"],
|
|
136
|
+
label=row["label"],
|
|
137
|
+
arg_name=row["arg_name"],
|
|
138
|
+
value_label_group=row["value_label_group"],
|
|
139
|
+
include_if_empty=row["include_if_empty"] == "Y",
|
|
140
|
+
empty_display=row["empty_display"],
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _field_value(
|
|
145
|
+
field: OrderConfirmationField,
|
|
146
|
+
*,
|
|
147
|
+
command: OrderConfirmationCommand,
|
|
148
|
+
args: argparse.Namespace,
|
|
149
|
+
value_labels: dict[tuple[str, str], str],
|
|
150
|
+
) -> str:
|
|
151
|
+
if field.arg_name == "__kind__":
|
|
152
|
+
value = command.kind
|
|
153
|
+
else:
|
|
154
|
+
value = getattr(args, field.arg_name, "")
|
|
155
|
+
if value is None:
|
|
156
|
+
value = ""
|
|
157
|
+
value = str(value)
|
|
158
|
+
if value and field.value_label_group:
|
|
159
|
+
return value_labels.get((field.value_label_group, value), value)
|
|
160
|
+
return value
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _format_order_confirmation_pretty(payload: dict[str, Any]) -> str:
|
|
164
|
+
lines = [payload["message"], "", "주문 확인:"]
|
|
165
|
+
for row in payload["_display_rows"]:
|
|
166
|
+
lines.append(f"- {row['label']}: {row['value']}")
|
|
167
|
+
return "\n".join(lines)
|
kiwoom_cli/output.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Output formatting for CLI command results."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any, Iterable
|
|
7
|
+
|
|
8
|
+
from kiwoom.core.types import KiwoomResponse
|
|
9
|
+
from kiwoom_cli.errors import CliInternalError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
OUTPUT_FORMATS = ("pretty", "json", "jsonl", "yaml")
|
|
13
|
+
ACCOUNT_IDENTIFIER_FIELDS = frozenset(
|
|
14
|
+
{
|
|
15
|
+
"acctNo",
|
|
16
|
+
"acctno",
|
|
17
|
+
"acct_no",
|
|
18
|
+
"account_no",
|
|
19
|
+
"account_number",
|
|
20
|
+
"acnt_no",
|
|
21
|
+
"acntNo",
|
|
22
|
+
"acntno",
|
|
23
|
+
"acnt_num",
|
|
24
|
+
"cano",
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
# Order numbers are operational identifiers the user needs to manage their own
|
|
28
|
+
# orders (e.g. read an `ord_no` from a buy/list response and pass it to
|
|
29
|
+
# modify/cancel), so they are NOT redacted. Account numbers are sensitive PII
|
|
30
|
+
# and stay redacted.
|
|
31
|
+
ACCOUNT_REDACT_FIELDS = ACCOUNT_IDENTIFIER_FIELDS
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def format_response(
|
|
35
|
+
response: KiwoomResponse,
|
|
36
|
+
*,
|
|
37
|
+
output_format: str = "pretty",
|
|
38
|
+
redact_fields: Iterable[str] = (),
|
|
39
|
+
) -> str:
|
|
40
|
+
return format_payload(response.body, output_format=output_format, redact_fields=redact_fields)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def format_payload(
|
|
44
|
+
payload: Any,
|
|
45
|
+
*,
|
|
46
|
+
output_format: str = "pretty",
|
|
47
|
+
redact_fields: Iterable[str] = (),
|
|
48
|
+
) -> str:
|
|
49
|
+
payload = _redact_payload(payload, set(redact_fields))
|
|
50
|
+
|
|
51
|
+
if output_format == "pretty":
|
|
52
|
+
return json.dumps(payload, ensure_ascii=False, indent=2)
|
|
53
|
+
if output_format == "json":
|
|
54
|
+
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
|
|
55
|
+
if output_format == "jsonl":
|
|
56
|
+
return _to_jsonl(payload)
|
|
57
|
+
if output_format == "yaml":
|
|
58
|
+
return _to_yaml(payload)
|
|
59
|
+
raise CliInternalError(f"지원하지 않는 출력 형식입니다: {output_format}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _to_jsonl(payload: Any) -> str:
|
|
63
|
+
rows = payload if isinstance(payload, list) else [payload]
|
|
64
|
+
return "\n".join(
|
|
65
|
+
json.dumps(row, ensure_ascii=False, separators=(",", ":")) for row in rows
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _redact_payload(value: Any, redact_fields: set[str]) -> Any:
|
|
70
|
+
if not redact_fields:
|
|
71
|
+
return value
|
|
72
|
+
if isinstance(value, dict):
|
|
73
|
+
return {
|
|
74
|
+
key: _redact_sensitive_value(item)
|
|
75
|
+
if _should_redact_key(key, redact_fields)
|
|
76
|
+
else _redact_payload(item, redact_fields)
|
|
77
|
+
for key, item in value.items()
|
|
78
|
+
}
|
|
79
|
+
if isinstance(value, list):
|
|
80
|
+
return [_redact_payload(item, redact_fields) for item in value]
|
|
81
|
+
return value
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _should_redact_key(key: Any, redact_fields: set[str]) -> bool:
|
|
85
|
+
text = str(key)
|
|
86
|
+
return text in redact_fields or text.lower() in redact_fields
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _redact_sensitive_value(value: Any) -> Any:
|
|
90
|
+
if isinstance(value, dict):
|
|
91
|
+
return {key: _redact_sensitive_value(item) for key, item in value.items()}
|
|
92
|
+
if isinstance(value, list):
|
|
93
|
+
return [_redact_sensitive_value(item) for item in value]
|
|
94
|
+
return _redact_value(value)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _redact_value(value: Any) -> Any:
|
|
98
|
+
if value is None:
|
|
99
|
+
return None
|
|
100
|
+
text = str(value)
|
|
101
|
+
if len(text) <= 4:
|
|
102
|
+
return "****"
|
|
103
|
+
return f"{'*' * (len(text) - 4)}{text[-4:]}"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _to_yaml(value: Any, *, indent: int = 0) -> str:
|
|
107
|
+
prefix = " " * indent
|
|
108
|
+
if isinstance(value, dict):
|
|
109
|
+
lines: list[str] = []
|
|
110
|
+
for key, item in value.items():
|
|
111
|
+
if isinstance(item, (dict, list)):
|
|
112
|
+
lines.append(f"{prefix}{key}:")
|
|
113
|
+
lines.append(_to_yaml(item, indent=indent + 2))
|
|
114
|
+
else:
|
|
115
|
+
lines.append(f"{prefix}{key}: {_yaml_scalar(item)}")
|
|
116
|
+
return "\n".join(lines)
|
|
117
|
+
if isinstance(value, list):
|
|
118
|
+
lines = []
|
|
119
|
+
for item in value:
|
|
120
|
+
if isinstance(item, (dict, list)):
|
|
121
|
+
lines.append(f"{prefix}-")
|
|
122
|
+
lines.append(_to_yaml(item, indent=indent + 2))
|
|
123
|
+
else:
|
|
124
|
+
lines.append(f"{prefix}- {_yaml_scalar(item)}")
|
|
125
|
+
return "\n".join(lines)
|
|
126
|
+
return f"{prefix}{_yaml_scalar(value)}"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _yaml_scalar(value: Any) -> str:
|
|
130
|
+
if value is None:
|
|
131
|
+
return "null"
|
|
132
|
+
if isinstance(value, bool):
|
|
133
|
+
return "true" if value else "false"
|
|
134
|
+
if isinstance(value, (int, float)):
|
|
135
|
+
return str(value)
|
|
136
|
+
return json.dumps(str(value), ensure_ascii=False)
|
kiwoom_cli/registry.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Load curated CLI command mappings."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import csv
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from functools import lru_cache
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from kiwoom_cli.errors import CliInternalError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
MAP_PATH = Path(__file__).resolve().parent / "maps" / "api_commands.csv"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class CommandDefinition:
|
|
18
|
+
api_id: str
|
|
19
|
+
api_name: str
|
|
20
|
+
cli_group: str
|
|
21
|
+
cli_command: str
|
|
22
|
+
command_path: str
|
|
23
|
+
status: str
|
|
24
|
+
coverage_status: str
|
|
25
|
+
safety_policy: str
|
|
26
|
+
method: str
|
|
27
|
+
path: str
|
|
28
|
+
required_body_fields: tuple[str, ...]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def load_command_definitions(map_path: Path | None = None) -> list[CommandDefinition]:
|
|
32
|
+
resolved_path = map_path or MAP_PATH
|
|
33
|
+
if map_path is None:
|
|
34
|
+
return list(_load_default_command_definitions())
|
|
35
|
+
return _load_command_definitions_from_path(resolved_path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@lru_cache(maxsize=1)
|
|
39
|
+
def _load_default_command_definitions() -> tuple[CommandDefinition, ...]:
|
|
40
|
+
return tuple(_load_command_definitions_from_path(MAP_PATH))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _load_command_definitions_from_path(resolved_path: Path) -> list[CommandDefinition]:
|
|
44
|
+
with resolved_path.open(encoding="utf-8", newline="") as file:
|
|
45
|
+
return [_definition_from_row(row) for row in csv.DictReader(file)]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_implemented_command(group: str, command: str) -> CommandDefinition:
|
|
49
|
+
matches = [
|
|
50
|
+
definition
|
|
51
|
+
for definition in load_command_definitions()
|
|
52
|
+
if definition.cli_group == group
|
|
53
|
+
and definition.cli_command == command
|
|
54
|
+
and definition.status == "implemented"
|
|
55
|
+
]
|
|
56
|
+
if not matches:
|
|
57
|
+
raise CliInternalError(f"구현된 명령을 찾을 수 없습니다: kiwoom {group} {command}")
|
|
58
|
+
if len(matches) > 1:
|
|
59
|
+
api_ids = ", ".join(definition.api_id for definition in matches)
|
|
60
|
+
raise CliInternalError(f"구현된 명령 매핑이 중복됩니다: kiwoom {group} {command} ({api_ids})")
|
|
61
|
+
return matches[0]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_command_by_path(command_path: str) -> CommandDefinition:
|
|
65
|
+
matches = [
|
|
66
|
+
definition
|
|
67
|
+
for definition in load_command_definitions()
|
|
68
|
+
if definition.command_path == command_path
|
|
69
|
+
]
|
|
70
|
+
if not matches:
|
|
71
|
+
raise CliInternalError(f"명령 매핑을 찾을 수 없습니다: {command_path}")
|
|
72
|
+
if len(matches) > 1:
|
|
73
|
+
api_ids = ", ".join(definition.api_id for definition in matches)
|
|
74
|
+
raise CliInternalError(f"명령 경로 매핑이 중복됩니다: {command_path} ({api_ids})")
|
|
75
|
+
return matches[0]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _definition_from_row(row: dict[str, str]) -> CommandDefinition:
|
|
79
|
+
return CommandDefinition(
|
|
80
|
+
api_id=row["api_id"],
|
|
81
|
+
api_name=row["api_name"],
|
|
82
|
+
cli_group=row["cli_group"],
|
|
83
|
+
cli_command=row["cli_command"],
|
|
84
|
+
command_path=row["command_path"],
|
|
85
|
+
status=row["status"],
|
|
86
|
+
coverage_status=row["coverage_status"],
|
|
87
|
+
safety_policy=row["safety_policy"],
|
|
88
|
+
method=row["method"],
|
|
89
|
+
path=row["path"],
|
|
90
|
+
required_body_fields=_split_fields(row["required_body_fields"]),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _split_fields(value: str) -> tuple[str, ...]:
|
|
95
|
+
return tuple(part.strip() for part in value.split(";") if part.strip())
|
kiwoom_cli/safety.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Safety policy checks for CLI command execution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from kiwoom_cli.errors import CliInputError, CliInternalError
|
|
6
|
+
from kiwoom_cli.registry import CommandDefinition
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def enforce_before_request(definition: CommandDefinition, *, confirm: bool = False) -> None:
|
|
10
|
+
if definition.coverage_status == "planned":
|
|
11
|
+
raise CliInternalError(f"{definition.command_path}: 아직 실행 정책과 명령 UX가 확정되지 않은 명령입니다.")
|
|
12
|
+
|
|
13
|
+
if definition.safety_policy in {"read", "account_read", "auth_write"}:
|
|
14
|
+
return
|
|
15
|
+
|
|
16
|
+
if definition.coverage_status == "preview-only":
|
|
17
|
+
raise CliInternalError(f"{definition.command_path}: 미리보기 전용 명령이라 실제 쓰기 요청을 전송할 수 없습니다.")
|
|
18
|
+
|
|
19
|
+
if definition.safety_policy == "order_write" and not confirm:
|
|
20
|
+
raise CliInputError(f"{definition.command_path}: 실제 주문 전송에는 --confirm 옵션이 필요합니다.")
|
|
21
|
+
|
|
22
|
+
if definition.safety_policy == "review_required":
|
|
23
|
+
raise CliInternalError(f"{definition.command_path}: 실행 전에 정책 검토가 필요한 명령입니다.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def enforce_before_preview(definition: CommandDefinition) -> None:
|
|
27
|
+
if definition.safety_policy != "order_write":
|
|
28
|
+
raise CliInternalError(f"{definition.command_path}: 요청 미리보기를 지원하지 않는 명령입니다.")
|
|
29
|
+
if definition.coverage_status not in {"preview-only", "guarded"}:
|
|
30
|
+
raise CliInternalError(f"{definition.command_path}: 현재 적용 상태에서는 요청 미리보기를 사용할 수 없습니다.")
|