-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
120 lines (107 loc) · 5.09 KB
/
Copy pathmain.py
File metadata and controls
120 lines (107 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: utf-8 -*-
# Copyright (c) 2026 shing1211
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""财报期权筛选 (get_option_earnings_screener + get_option_event + get_option_underlying_overview)
Demonstrates:
- get_option_earnings_screener: screen stocks with earnings events & active options
- get_option_event: list unusual option activity
- get_option_underlying_overview: batch underlying overview (IV, HV, volume, OI)
"""
import logging
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
import futu as ft
from connect import create_quote_context
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s")
logger = logging.getLogger(__name__)
if __name__ == "__main__":
logger.info("=== Earnings Options Dashboard (SDK 10.8.6808+) ===\n")
ctx = create_quote_context()
try:
logger.info("── Earnings Options Screener (US, Top 5 by Volume) ──")
ret, data = ctx.get_option_earnings_screener(
ft.OptionMarket.US_SECURITY,
sort_type=ft.EarningsSortType.VOLUME,
is_asc=False,
count=5,
)
if ret != ft.RET_OK:
logger.error("get_option_earnings_screener failed: %s", data)
elif data is not None and not data.empty:
logger.info(" %d results", len(data))
for _, row in data.iterrows():
logger.info(" %-16s vol=%-8s OI=%-8s IV=%-6s IV%%=%-6s exp=%s",
row.get("owner", "?"),
row.get("volume", "?"),
row.get("open_interest", "?"),
row.get("iv", "?"),
row.get("iv_rank", row.get("iv_percentile", "?")),
row.get("strike_date_time", row.get("strike_date_timestamp", "?")))
else:
logger.info(" (server returned empty)\n")
codes = ["US.AAPL", "US.NVDA", "US.TSLA", "US.MSFT", "US.AMZN"]
logger.info("\n── Option Underlying Overview (Top US tech) ──")
ret, data = ctx.get_option_underlying_overview(codes, ft.IndexOptionType.NORMAL)
if ret == ft.RET_OK and data is not None and not data.empty:
for _, row in data.iterrows():
logger.info(" %-16s spot=%-8s IV=%-6s HV=%-6s vol=%-8s OI=%-8s",
row.get("code", "?"),
row.get("price", row.get("last_price", "?")),
row.get("iv", "?"),
row.get("hv", "?"),
row.get("volume", "?"),
row.get("open_interest", "?"))
else:
logger.info(" (no overview data)\n")
logger.info("\n── Unusual Option Activity (US, last 10) ──")
ret, data = ctx.get_option_event(
ft.OptionMarket.US_SECURITY,
count=10,
)
if ret == ft.RET_OK and data is not None and not data.empty:
logger.info(" %d events", len(data))
for _, row in data.iterrows():
logger.info(" %-16s strategy=%-12s sentiment=%-8s vol=%-8s OI=%-6s IV=%-6s",
row.get("owner", "?"),
row.get("strategy", "?"),
row.get("sentiment", "?"),
row.get("volume", "?"),
row.get("open_interest", "?"),
row.get("iv", "?"))
else:
logger.info(" (no unusual activity)\n")
logger.info("\n── Unusual Option Activity with Filters (US, Put Sweep, >1000 vol) ──")
filters = [
ft.OptionEventFilter(ft.EventIndicatorType.STRATEGY, string_value_list=["SWEEP"]),
ft.OptionEventFilter(ft.EventIndicatorType.SENTIMENT, string_value_list=["PUT"]),
ft.OptionEventFilter(ft.EventIndicatorType.VOLUME, interval_min=1000),
]
ret, data = ctx.get_option_event(
ft.OptionMarket.US_SECURITY,
count=5,
filter_list=filters,
)
if ret == ft.RET_OK and data is not None and not data.empty:
for _, row in data.iterrows():
logger.info(" %-16s time=%-12s vol=%-8s price=%-8s",
row.get("owner", "?"),
row.get("time", "?"),
row.get("volume", "?"),
row.get("price", "?"))
else:
logger.info(" (no filtered results)\n")
finally:
ctx.close()
logger.info("Done.")