iLOVE2D's picture
Upload 2846 files
5374a2d verified
# Main function to run
import sys
import os
from datetime import datetime
from pathlib import Path
from dotenv import load_dotenv
import time
# Set matplotlib backend to avoid threading issues
import matplotlib
matplotlib.use('Agg')
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
from catl_data_functions import fetch_stock_data
from stock_chart_tools import generate_stock_charts
# EvoAgentX imports
from evoagentx.models import OpenAILLMConfig, OpenAILLM, OpenRouterConfig, OpenRouterLLM
from evoagentx.workflow import WorkFlowGraph, WorkFlow, WorkFlowGenerator
from evoagentx.agents import AgentManager
from evoagentx.tools import StorageToolkit, CMDToolkit
load_dotenv()
# Read API keys from files
def read_api_key(filename):
try:
with open(filename, 'r', encoding='utf-8') as f:
return f.read().strip()
except FileNotFoundError:
return None
OPENAI_API_KEY = read_api_key("openai_api_key.txt") or os.getenv("OPENAI_API_KEY")
OPEN_ROUTER_API_KEY = read_api_key("openrouter_api_key.txt") or os.getenv("OPENROUTER_API_KEY")
# Fixed variables and paths
available_funds = 100000
current_positions = 500
average_price = 280
position_type = "call"
report_date = datetime.now().strftime('%Y-%m-%d')
llm = OpenAILLM(config=OpenAILLMConfig(model="gpt-4o-mini", openai_key=OPENAI_API_KEY, stream=True, output_response=True, max_tokens=16000))
tools = [StorageToolkit(), CMDToolkit()]
# Path to the workflow module (should be pre-generated)
module_save_path = "invest_demo_4o_mini_v1.json"
# Workflow generation goal (commented out for future use)
WORKFLOW_GOAL = """Create a daily trading decision workflow for A-share stocks.
## Workflow Overview:
A multi-step workflow for daily trading decisions with fixed capital, making trading decisions based on market data and current positions.
## Task Description:
**Name:** daily_trading_decision
**Description:** A comprehensive trading decision system that analyzes market data and generates daily trading operations with detailed analysis.
## Input:
- **goal** (string): Contains stock code, available funds, current positions, data folder path, output file path, and optional past report path
## Output:
- **trading_report** (string): A comprehensive daily trading report with complete analysis
## Analysis Requirements:
The workflow should analyze three key aspects of the stock:
1. **Background Analysis**: Market environment, industry trends, news sentiment, expert opinions, economic factors, and regulatory environment that affect stock prices
2. **Price Analysis**: Historical price patterns, technical indicators, support/resistance levels, and trading volume analysis
3. **Performance Review**: Past trading decisions, performance evaluation, and lessons learned from previous reports
## Workflow Structure:
- Start with file discovery to identify and categorize available data sources
- Perform the three analyses in parallel where possible for efficiency
- Compile all findings into a comprehensive trading report
## Agent Guidelines:
- Agents should use appropriate tools to discover and read files from the data folder
- Each analysis should focus on its specific domain without overlap
- Agents should filter out irrelevant files and focus on data relevant to their analysis
- All analysis must be based on actual data from files - no fake or estimated data
- Present complete data without omissions or truncations
## Report Structure:
The final report should include:
1. **Background Analysis**: Market environment and external factors
2. **Price Analysis**: Technical patterns and indicators
3. **Performance Review**: Historical performance and lessons learned
4. **Trading Recommendations**: Specific buy/sell/hold decisions with quantities and prices
## Critical Requirements:
- Base all analysis on actual data read from files
- If no relevant files are found, report this clearly and do not make up data
- Provide specific trading recommendations with quantities and price targets
- Consider current positions and available capital in decision making
- Structure the report with clear sections and data tables
- Return complete analysis without summarization
"""
def get_directories(stock_code, timestamp):
"""Get directory paths for a given stock code and timestamp"""
base_dir = Path(f"./{stock_code}")
data_dir = base_dir / timestamp / "data"
report_dir = base_dir / "reports"
graphs_dir = base_dir / timestamp / "graphs"
return base_dir, data_dir, report_dir, graphs_dir
def check_data_exists(data_dir):
"""Check if data files already exist in the data directory"""
if not data_dir.exists():
return False
# Check for common data file patterns
expected_files = [
"stock_daily_catl_*.csv",
"china_cpi_*.csv",
"china_gdp_yearly_*.csv",
"industry_fund_flow_*.csv",
"stock_news_catl_*.csv",
"market_summary_sse_*.csv",
"market_indices_*.csv",
"option_volatility_50etf_*.csv",
"institution_recommendation_catl_*.csv"
]
existing_files = list(data_dir.glob("*.csv"))
if len(existing_files) >= 5: # At least 5 data files exist
print(f"✅ 数据文件已存在: {data_dir}")
print(f" 发现 {len(existing_files)} 个数据文件")
return True
return False
def check_charts_exist(graphs_dir, stock_code):
"""Check if chart files already exist"""
if not graphs_dir.exists():
return False
expected_charts = [
f"{stock_code}_technical_charts.png",
f"{stock_code}_candlestick_chart.png"
]
existing_charts = [f.name for f in graphs_dir.glob("*.png")]
if all(chart in existing_charts for chart in expected_charts):
print(f"✅ 图表文件已存在: {graphs_dir}")
print(f" 发现 {len(existing_charts)} 个图表文件")
return True
return False
def generate_workflow():
"""Generate a new workflow (commented out for future use)"""
# Uncomment the following lines to generate a new workflow
wf_generator = WorkFlowGenerator(llm=llm, tools=tools)
workflow_graph: WorkFlowGraph = wf_generator.generate_workflow(goal=WORKFLOW_GOAL, retry=5)
workflow_graph.save_module(module_save_path)
return workflow_graph
def execute_workflow(stock_code, data_dir, report_dir, timestamp):
"""Execute the workflow with the given parameters"""
try:
# Load workflow graph
workflow_graph: WorkFlowGraph = WorkFlowGraph.from_file(module_save_path)
agent_manager = AgentManager(tools=tools)
agent_manager.add_agents_from_workflow(workflow_graph, llm_config=llm.config)
workflow = WorkFlow(graph=workflow_graph, agent_manager=agent_manager, llm=llm)
workflow.init_module()
# Construct the goal string
output_file = report_dir / f"text_report_{stock_code}_{timestamp}.md"
past_report = report_dir / f"text_report_{stock_code}_{timestamp}_previous.md"
goal = f"""I need a daily trading decision for stock {stock_code}.
Available funds: {available_funds} RMB
Current positions: {current_positions} shares of {stock_code} at average price {average_price} RMB
Date: {report_date}
Type of position: {position_type}
Data folder: {data_dir}
Past report folder: {past_report}
Please read ALL files in the data folder and generate a comprehensive trading decision report in Chinese based on real data. Return the complete content.
"""
output = workflow.execute({"goal": goal})
try:
with open(output_file, "w", encoding="utf-8") as f:
f.write(output)
print(f"Trading decision report saved to: {output_file}")
# # Also save a backup
# with open(report_dir / f"text_report_{stock_code}_{timestamp}_back.md", "w", encoding="utf-8") as f:
# f.write(output)
except Exception as e:
print(f"Error saving report: {e}")
except Exception as e:
print(f"Error executing workflow: {e}")
import traceback
traceback.print_exc()
def generate_html_report(stock_code, base_dir, report_dir, graphs_dir, timestamp):
"""Generate HTML report from markdown and charts"""
try:
# Import the HTML generator
from html_report_generator import HTMLGenerator
# Define file paths
md_file = report_dir / f"text_report_{stock_code}_{timestamp}.md"
html_output = base_dir/ datetime.now().strftime('%Y%m%d') / "html_report" / f"report_{stock_code}_{timestamp}.html"
# Find chart files
technical_chart = graphs_dir / f"{stock_code}_technical_charts.png"
price_volume_chart = graphs_dir / f"{stock_code}_candlestick_chart.png"
# Check if markdown file exists
if not md_file.exists():
print(f"❌ Markdown file not found: {md_file}")
return False
# Check if charts exist
if not technical_chart.exists():
print(f"⚠️ Technical chart not found: {technical_chart}")
technical_chart = ""
if not price_volume_chart.exists():
print(f"⚠️ Price/volume chart not found: {price_volume_chart}")
price_volume_chart = ""
# Generate HTML report
print(f"[4] 生成HTML报告: {html_output}")
generator = HTMLGenerator(str(html_output))
output_file = generator.generate_report(
str(md_file),
str(technical_chart) if technical_chart else "",
str(price_volume_chart) if price_volume_chart else ""
)
print(f"✅ HTML报告生成成功: {output_file}")
print(f"📁 资源文件夹: {Path(output_file).parent / 'assets'}")
print(f"🌐 在浏览器中打开HTML文件查看报告")
return True
except Exception as e:
print(f"❌ HTML报告生成失败: {e}")
import traceback
traceback.print_exc()
return False
def generate_html_from_existing_files(stock_code, timestamp=None):
"""Generate HTML report from existing markdown and chart files"""
if timestamp is None:
timestamp = datetime.now().strftime('%Y%m%d')
base_dir, data_dir, report_dir, graphs_dir = get_directories(stock_code, timestamp)
print(f"🔍 查找现有文件:")
print(f" 报告目录: {report_dir}")
print(f" 图表目录: {graphs_dir}")
# Check if directories exist
if not report_dir.exists():
print(f"❌ 报告目录不存在: {report_dir}")
return False
if not graphs_dir.exists():
print(f"⚠️ 图表目录不存在: {graphs_dir}")
graphs_dir = None
return generate_html_report(stock_code, base_dir, report_dir, graphs_dir, timestamp)
def main():
if len(sys.argv) < 2:
stock_code = input("请输入股票代码 (如300750): ").strip()
else:
stock_code = sys.argv[1].strip()
if not stock_code.isdigit():
print("❌ 股票代码应为数字!")
return
# stock_code = "300750"
timestamp = datetime.now().strftime('%Y%m%d')
base_dir, data_dir, report_dir, graphs_dir = get_directories(stock_code, timestamp)
data_dir.mkdir(parents=True, exist_ok=True)
report_dir.mkdir(parents=True, exist_ok=True)
graphs_dir.mkdir(parents=True, exist_ok=True)
# Check and fetch data if needed
if not check_data_exists(data_dir):
print(f"\n[1] 拉取数据到: {data_dir}")
fetch_stock_data(stock_code, output_dir=str(data_dir))
else:
print(f"\n[1] 跳过数据拉取 (数据已存在)")
# Check and generate charts if needed
if not check_charts_exist(graphs_dir, stock_code):
print(f"[2] 生成图表到: {graphs_dir}")
generate_stock_charts(stock_code, output_dir=str(graphs_dir))
else:
print(f"[2] 跳过图表生成 (图表已存在)")
# === Workflow logic from workflow_invest.py ===
print(f"[3] 生成报告到: {report_dir}")
# generate_workflow(llm, tools)
execute_workflow(stock_code, data_dir, report_dir, timestamp)
# === Generate HTML report ===
print(f"\n[4] 生成HTML报告")
html_success = generate_html_report(stock_code, base_dir, report_dir, graphs_dir, timestamp)
if html_success:
print("\n✅ 全部流程完成!包括HTML报告生成")
else:
print("\n✅ 主要流程完成!(HTML报告生成失败)")
if __name__ == "__main__":
main()