Add files via upload

1. 增加了港股支持
2. 补全Dockerfile
3. 支持HTML在线访问
This commit is contained in:
兰志宏
2025-03-01 17:03:25 +08:00
committed by GitHub
parent b0180b25d5
commit 9a3d87ed56
4 changed files with 113 additions and 18 deletions

27
Dockerfile Normal file
View File

@@ -0,0 +1,27 @@
# 使用 Python 3.9 作为基础镜像
FROM python:3.10-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
libgl1-mesa-glx \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# 复制项目文件
COPY . /app/
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install akshare --upgrade -i https://pypi.org/simple
# 设置环境变量
ENV PYTHONPATH=/app
# 暴露端口(如果需要)
EXPOSE 8888
# 启动命令
CMD ["python", "web_server.py"]

View File

@@ -1,5 +1,5 @@
# 基础科学计算和数据处理库 # 基础科学计算和数据处理库
numpy==2.0.0 numpy==2.1.2
pandas==2.2.2 pandas==2.2.2
scipy==1.15.1 scipy==1.15.1
@@ -7,9 +7,6 @@ scipy==1.15.1
akshare==1.15.87 akshare==1.15.87
tqdm==4.67.1 tqdm==4.67.1
# GUI库
PyQt6==6.8.1
markdown2==2.5.3
# 网络和API请求 # 网络和API请求
requests==2.32.3 requests==2.32.3

View File

@@ -18,7 +18,7 @@ class StockAnalyzer:
load_dotenv() load_dotenv()
# 设置 Gemini API # 设置 Gemini API
self.gemini_api_url = "https://api.xxx.xxx" self.gemini_api_url = os.getenv('GEMINI_API_URL')
self.gemini_api_key = os.getenv('GEMINI_API_KEY') self.gemini_api_key = os.getenv('GEMINI_API_KEY')
# 配置参数 # 配置参数
@@ -31,7 +31,14 @@ class StockAnalyzer:
'atr_period': 14 'atr_period': 14
} }
def get_stock_data(self, stock_code, start_date=None, end_date=None): # 添加市场类型枚举
self.MARKET_TYPES = {
'A': 'A股',
'HK': '港股',
'CRYPTO': '加密货币'
}
def get_stock_data(self, stock_code, market_type='A', start_date=None, end_date=None, ):
"""获取股票数据""" """获取股票数据"""
import akshare as ak import akshare as ak
@@ -41,11 +48,26 @@ class StockAnalyzer:
end_date = datetime.now().strftime('%Y%m%d') end_date = datetime.now().strftime('%Y%m%d')
try: try:
# 使用 akshare 获取股票数据 # 根据市场类型获取数据
df = ak.stock_zh_a_hist(symbol=stock_code, if market_type == 'A':
start_date=start_date, df = ak.stock_zh_a_hist(
end_date=end_date, symbol=stock_code,
adjust="qfq") start_date=start_date,
end_date=end_date,
adjust="qfq"
)
# A股数据列名映射
elif market_type == 'HK':
df = ak.stock_hk_daily(
symbol=stock_code,
adjust="qfq"
)
elif market_type == 'CRYPTO':
df = ak.crypto_js_spot(
symbol=stock_code
)
else:
raise ValueError(f"不支持的市场类型: {market_type}")
# 重命名列名以匹配分析需求 # 重命名列名以匹配分析需求
df = df.rename(columns={ df = df.rename(columns={
@@ -225,7 +247,7 @@ class StockAnalyzer:
} }
data = { data = {
"model": "gemini-1.5-flash", "model": os.getenv('GEMINI_API_MODEL'),
"messages": [{"role": "user", "content": prompt}] "messages": [{"role": "user", "content": prompt}]
} }
@@ -233,8 +255,11 @@ class StockAnalyzer:
f"{self.gemini_api_url}/v1/chat/completions", f"{self.gemini_api_url}/v1/chat/completions",
headers=headers, headers=headers,
json=data, json=data,
timeout=10 timeout=30
) )
print(headers)
print(data)
print(response.json())
if response.status_code == 200: if response.status_code == 200:
return response.json()['choices'][0]['message']['content'] return response.json()['choices'][0]['message']['content']
@@ -258,11 +283,11 @@ class StockAnalyzer:
else: else:
return '强烈建议卖出' return '强烈建议卖出'
def analyze_stock(self, stock_code): def analyze_stock(self, stock_code, market_type='A'):
"""分析单个股票""" """分析单个股票"""
try: try:
# 获取股票数据 # 获取股票数据
df = self.get_stock_data(stock_code) df = self.get_stock_data(stock_code, market_type)
# 计算技术指标 # 计算技术指标
df = self.calculate_indicators(df) df = self.calculate_indicators(df)
@@ -295,13 +320,13 @@ class StockAnalyzer:
self.logger.error(f"分析股票时出错: {str(e)}") self.logger.error(f"分析股票时出错: {str(e)}")
raise raise
def scan_market(self, stock_list, min_score=60): def scan_market(self, stock_list, min_score=60, market_type='A'):
"""扫描市场,寻找符合条件的股票""" """扫描市场,寻找符合条件的股票"""
recommendations = [] recommendations = []
for stock_code in stock_list: for stock_code in stock_list:
try: try:
report = self.analyze_stock(stock_code) report = self.analyze_stock(stock_code, market_type)
if report['score'] >= min_score: if report['score'] >= min_score:
recommendations.append(report) recommendations.append(report)
except Exception as e: except Exception as e:

46
web_server.py Normal file
View File

@@ -0,0 +1,46 @@
from flask import Flask, render_template, request, jsonify
from stock_analyzer import StockAnalyzer
import threading
import logging
from logging.handlers import RotatingFileHandler
import traceback
app = Flask(__name__)
analyzer = StockAnalyzer()
# 配置日志
logging.basicConfig(level=logging.INFO)
handler = RotatingFileHandler('flask_app.log', maxBytes=10000000, backupCount=5)
handler.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
))
app.logger.addHandler(handler)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/analyze', methods=['POST'])
def analyze():
try:
data = request.json
stock_codes = data.get('stock_codes', [])
market_type = data.get('market_type', 'A')
if not stock_codes:
return jsonify({'error': '请输入代码'}), 400
results = []
for stock_code in stock_codes:
result = analyzer.analyze_stock(stock_code.strip(), market_type)
results.append(result)
return jsonify({'results': results})
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
# 将 host 设置为 '0.0.0.0' 使其支持所有网络接口访问
app.run(host='0.0.0.0', port=8888, debug=True)