-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
executable file
·319 lines (269 loc) · 12.2 KB
/
Copy pathmain.py
File metadata and controls
executable file
·319 lines (269 loc) · 12.2 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#!/usr/bin/env python3
"""
CL Option Zone - Main Calculator
支持互動式參數詢問與命令行參數兩種模式
"""
import sys
import os
import argparse
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.layout import Layout
# Add project root to path
sys.path.insert(0, os.path.dirname(__file__))
from core.data_loader import DataLoader
from core.volume_profile import VolumeProfileAnalyzer
from core.support_strength import SupportStrengthAnalyzer
from core.interactive_input import InteractiveInput
console = Console()
def main():
parser = argparse.ArgumentParser(description="CL Volume Profile & Option Zone Calculator")
parser.add_argument("--interactive", "-i", action="store_true", help="啟用互動式參數詢問 / Enable interactive parameter input")
parser.add_argument("--symbol", type=str, default="CL=F", help="Ticker Symbol (default: CL=F)")
parser.add_argument("--period", type=str, default="5d", help="Lookback period (e.g. 5d, 1mo)")
parser.add_argument("--bins", type=int, default=150, help="Number of price bins")
parser.add_argument("--lang", type=str, default="zh-TW", choices=["zh-TW", "en"], help="Language / 語言")
args = parser.parse_args()
# 互動式模式
if args.interactive:
run_interactive_mode()
else:
run_command_mode(args)
def run_interactive_mode():
"""執行互動式參數詢問模式"""
interactor = InteractiveInput()
settings = interactor.run_interactive()
if settings is None:
console.print("[yellow]操作已取消 / Operation cancelled[/]")
return
# 使用取得的設定執行分析
args = argparse.Namespace(
symbol=settings["symbol"],
period=settings["period"],
bins=settings["bins"]
)
# 根據語言設定顯示歡迎訊息
if settings["language"] == "zh-TW":
console.print(Panel.fit(f"[bold gold1]📊 CL 選擇權區域分析器[/]\n[dim]標的: {args.symbol} | 週期: {args.period}[/]", border_style="gold1"))
else:
console.print(Panel.fit(f"[bold gold1]📊 CL Option Zone Analyzer[/]\n[dim]Target: {args.symbol} | Period: {args.period}[/]", border_style="gold1"))
execute_analysis(args, settings["language"])
def run_command_mode(args):
"""執行命令行參數模式"""
lang = args.lang
if lang == "zh-TW":
console.print(Panel.fit(f"[bold gold1]📊 CL 選擇權區域分析器[/]\n[dim]標的: {args.symbol} | 週期: {args.period}[/]", border_style="gold1"))
else:
console.print(Panel.fit(f"[bold gold1]📊 CL Option Zone Analyzer[/]\n[dim]Target: {args.symbol} | Period: {args.period}[/]", border_style="gold1"))
execute_analysis(args, lang)
execute_analysis(args, lang)
def display_report(price, res, strength_res, lang="zh-TW"):
# 根據語言設定
if lang == "zh-TW":
titles = {
"key_levels": "🛡️ 關鍵價位與區域",
"metric": "指標",
"price_level": "價格",
"relation": "與現價關係",
"current_price": "現價",
"vah": "價值區高點 (VAH)",
"poc": "控制點 (POC)",
"val": "價值區低點 (VAL)",
"strength_ranking": "💪 支撐強度排名 (前15)",
"rank": "排名",
"strength_score": "強度分數",
"z_score": "Z分數",
"distance": "距離",
"inside_value": "【區間內】",
"above_value": "【區間上】(多頭/超買)",
"below_value": "【區間下】(空頭/折扣)",
"market_context": "市場環境",
"strategic_bias": "🎯 策略傾向",
"poc_target": "POC 回歸目標",
"vah_resistance": "VAH 阻力/突破點",
"val_support": "VAL 支撐/跌破點",
"high_volume_nodes": "⚠️ 高成交量節點 (結構性價位)",
"low_volume_nodes": "🚀 低成交量節點 (流動性真空)",
"analysis_title": "📊 量化分析"
}
else:
titles = {
"key_levels": "🛡️ Key Levels & Zones",
"metric": "Metric",
"price_level": "Price Level",
"relation": "Relation to Spot",
"current_price": "Current Price",
"vah": "VAH (Value Area High)",
"poc": "POC (Point of Control)",
"val": "VAL (Value Area Low)",
"strength_ranking": "💪 Support Strength Ranking (Top 15)",
"rank": "Rank",
"strength_score": "Strength Score",
"z_score": "Z-Score",
"distance": "Distance",
"inside_value": "[bold green]INSIDE VALUE[/]",
"above_value": "[bold red]ABOVE VALUE (Bullish/Overextended)[/]",
"below_value": "[bold blue]BELOW VALUE (Bearish/Discount)[/]",
"market_context": "Market Context",
"strategic_bias": "🎯 Strategic Bias",
"poc_target": "POC - Mean Reversion Target",
"vah_resistance": "VAH - Resistance / Breakout Level",
"val_support": "VAL - Support / Breakdown Level",
"high_volume_nodes": "⚠️ High Volume Nodes (Structural Levels)",
"low_volume_nodes": "🚀 Low Volume Nodes (Liquidity Voids)",
"analysis_title": "📊 Quantitative Analysis"
}
# Determine Trend/Zone
if lang == "zh-TW":
if price > res['VAH']:
zone_status = titles["above_value"]
elif price < res['VAL']:
zone_status = titles["below_value"]
else:
zone_status = titles["inside_value"]
else:
if price > res['VAH']:
zone_status = titles["above_value"]
elif price < res['VAL']:
zone_status = titles["below_value"]
else:
zone_status = titles["inside_value"]
# Main Table
table = Table(title=titles["key_levels"], show_header=True, header_style="bold magenta")
table.add_column(titles["metric"], style="cyan")
table.add_column(titles["price_level"], style="yellow", justify="right")
table.add_column(titles["relation"], style="white")
def get_diff(level):
diff = price - level
color = "red" if diff < 0 else "green"
return f"[{color}]{diff:+.2f}[/]"
table.add_row(titles["current_price"], f"{price:.2f}", "-")
table.add_row(titles["vah"], f"{res['VAH']}", get_diff(res['VAH']))
table.add_row(titles["poc"], f"[bold]{res['POC']}[/]", get_diff(res['POC']))
table.add_row(titles["val"], f"{res['VAL']}", get_diff(res['VAL']))
console.print(table)
# 支撐強度排名表
strength_table = Table(title=titles["strength_ranking"], show_header=True, header_style="bold gold1")
strength_table.add_column(titles["rank"], style="cyan", width=6)
strength_table.add_column(titles["price_level"], style="yellow", justify="right", width=10)
strength_table.add_column(titles["strength_score"], style="white", justify="right", width=14)
strength_table.add_column(titles["z_score"], style="magenta", justify="right", width=10)
strength_table.add_column(titles["distance"], style="dim", justify="right", width=10)
# 取前15名
top_n = 15
for i in range(min(top_n, len(strength_res['ranks']))):
rank = strength_res['ranks'][i]
level = strength_res['levels'][i]
score = strength_res['normalized'][i]
z_score = strength_res['z_scores'][i]
# 計算距離當前價格
distance = ((level - price) / price) * 100
distance_str = f"{distance:+.2f}%"
# 高亮POC/VAH/VAL
level_str = f"{level:.2f}"
if lang == "zh-TW":
if abs(level - res['POC']) < 0.5:
level_str = f"[bold yellow]{level:.2f} (POC)[/]"
elif abs(level - res['VAH']) < 0.5:
level_str = f"[bold red]{level:.2f} (VAH)[/]"
elif abs(level - res['VAL']) < 0.5:
level_str = f"[bold green]{level:.2f} (VAL)[/]"
else:
if abs(level - res['POC']) < 0.5:
level_str = f"[bold yellow]{level:.2f} (POC)[/]"
elif abs(level - res['VAH']) < 0.5:
level_str = f"[bold red]{level:.2f} (VAH)[/]"
elif abs(level - res['VAL']) < 0.5:
level_str = f"[bold green]{level:.2f} (VAL)[/]"
# 分數條形圖
bar_length = int(score / 5)
score_bar = "█" * bar_length
score_str = f"{score:6.2f} {score_bar}"
strength_table.add_row(
f"#{rank}",
level_str,
score_str,
f"{z_score:.2f}",
distance_str
)
console.print(strength_table)
# Strategy Signal
if lang == "zh-TW":
strat_panel = f"""
[bold underline]{titles['market_context']}[/]: {zone_status}
[bold]{titles['strategic_bias']}:[/bold]
• [bold yellow]{titles['poc_target']}: {res['POC']}
• [bold red]{titles['vah_resistance']}: {res['VAH']}
• [bold green]{titles['val_support']}: {res['VAL']}
[bold]{titles['high_volume_nodes']}:[/]
{', '.join([str(x) for x in res['HVNs']])}
[bold]{titles['low_volume_nodes']}:[/]
{', '.join([str(x) for x in res['LVNs']])}
"""
else:
strat_panel = f"""
[bold underline]{titles['market_context']}[/]: {zone_status}
[bold]{titles['strategic_bias']}:[/bold]
• [bold yellow]{titles['poc_target']}: {res['POC']}
• [bold red]{titles['vah_resistance']}: {res['VAH']}
• [bold green]{titles['val_support']}: {res['VAL']}
[bold]{titles['high_volume_nodes']}:[/]
{', '.join([str(x) for x in res['HVNs']])}
[bold]{titles['low_volume_nodes']}:[/]
{', '.join([str(x) for x in res['LVNs']])}
"""
console.print(Panel(strat_panel, title=titles["analysis_title"], border_style="cyan"))
def execute_analysis(args, lang="zh-TW"):
"""執行分析的核心邏輯"""
# 1. Load Data
loader = DataLoader(args.symbol)
# 根據語言設定訊息
if lang == "zh-TW":
status_messages = {
"fetching": "[bold green]正在獲取數據...[/]",
"loaded": f"✅ 數據已載入: [cyan]{{}}[/] 根K線。現價: [bold white]{{:.2f}}[/]",
"volume_profile": "[bold blue]計算成交量分布...[/]",
"support_strength": "[bold magenta]計算支撐強度...[/]",
"error_load": "[red]載入數據錯誤: {}[/]",
"error_analysis": "[red]分析錯誤: {}[/]"
}
else:
status_messages = {
"fetching": "[bold green]Fetching Data...[/]",
"loaded": f"✅ Data loaded: [cyan]{{}}[/] candles. Last Price: [bold white]{{:.2f}}[/]",
"volume_profile": "[bold blue]Calculating Volume Profile...[/]",
"support_strength": "[bold magenta]Calculating Support Strength...[/]",
"error_load": "[red]Error loading data: {}[/]",
"error_analysis": "[red]Analysis Error: {}[/]"
}
try:
with console.status(status_messages["fetching"]):
df = loader.fetch_data(period=args.period, interval="5m")
current_price = loader.get_latest_price()
console.print(status_messages["loaded"].format(len(df), current_price))
except Exception as e:
console.print(status_messages["error_load"].format(e))
return
# 2. Analyze
try:
with console.status(status_messages["volume_profile"]):
analyzer = VolumeProfileAnalyzer(df, n_bins=args.bins)
results = analyzer.calculate()
# 3. 支撐強度分析
with console.status(status_messages["support_strength"]):
strength_analyzer = SupportStrengthAnalyzer(
df,
analyzer.profile,
analyzer.bin_prices
)
strength_results = strength_analyzer.calculate(current_price)
except Exception as e:
console.print(status_messages["error_analysis"].format(e))
import traceback
console.print(traceback.format_exc())
return
# 4. Report
display_report(current_price, results, strength_results, lang)
if __name__ == "__main__":
main()