Remove files
This commit is contained in:
+236
-19
@@ -225,17 +225,35 @@ def get_a_stock_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time
|
||||
|
||||
if start_time:
|
||||
try:
|
||||
# 尝试解析时间戳(毫秒)
|
||||
start_timestamp = int(start_time)
|
||||
start_date = datetime.fromtimestamp(start_timestamp / 1000).strftime('%Y-%m-%d')
|
||||
except:
|
||||
start_date = start_time
|
||||
except (ValueError, TypeError):
|
||||
# 如果不是时间戳,尝试解析datetime-local格式 (YYYY-MM-DDTHH:MM)
|
||||
try:
|
||||
if 'T' in str(start_time):
|
||||
# datetime-local格式:2025-05-19T06:07
|
||||
start_date = str(start_time).split('T')[0] # 只取日期部分
|
||||
else:
|
||||
start_date = str(start_time)
|
||||
except:
|
||||
start_date = start_time
|
||||
|
||||
if end_time:
|
||||
try:
|
||||
# 尝试解析时间戳(毫秒)
|
||||
end_timestamp = int(end_time)
|
||||
end_date = datetime.fromtimestamp(end_timestamp / 1000).strftime('%Y-%m-%d')
|
||||
except:
|
||||
end_date = end_time
|
||||
except (ValueError, TypeError):
|
||||
# 如果不是时间戳,尝试解析datetime-local格式
|
||||
try:
|
||||
if 'T' in str(end_time):
|
||||
# datetime-local格式:2025-05-26T06:07
|
||||
end_date = str(end_time).split('T')[0] # 只取日期部分
|
||||
else:
|
||||
end_date = str(end_time)
|
||||
except:
|
||||
end_date = end_time
|
||||
|
||||
# 如果用户指定了时间范围,优先获取该范围内的所有数据
|
||||
actual_limit = limit
|
||||
@@ -328,22 +346,51 @@ def analyze_chan(df):
|
||||
klc_fx_info = []
|
||||
for klc in klc_list:
|
||||
if hasattr(klc, 'klc_fx_type') and klc.klc_fx_type != Chan_KLC_FX.UNKNOWN:
|
||||
# 计算分型强度
|
||||
#fx_strength = klc.calculate_fx_strength()
|
||||
fx_strength = klc.cal_fx_strength()
|
||||
fx_strength_level = klc.get_fx_strength_level()
|
||||
is_strong_fx = klc.is_strong_fx()
|
||||
if fx_strength < 1:
|
||||
try:
|
||||
# 计算分型强度
|
||||
fx_strength = 0
|
||||
klc_fx_info.append({
|
||||
'time': klc.end_time,
|
||||
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
|
||||
'fx_type': str(klc.klc_fx_type).replace("Chan_KLC_FX.", ""),
|
||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||
'fx_strength': fx_strength, # 分型强度分数 (0-100)
|
||||
'fx_strength_level': fx_strength_level, # 分型强度等级 (极强/强/中等/弱/极弱)
|
||||
'is_strong_fx': is_strong_fx # 是否为强分型
|
||||
})
|
||||
fx_strength_level = ""
|
||||
is_strong_fx = False
|
||||
|
||||
# 尝试调用分型强度计算方法
|
||||
if hasattr(klc, 'cal_fx_strength'):
|
||||
fx_strength = klc.cal_fx_strength()
|
||||
elif hasattr(klc, 'calculate_fx_strength'):
|
||||
fx_strength = klc.calculate_fx_strength()
|
||||
|
||||
# 尝试获取分型强度等级
|
||||
if hasattr(klc, 'get_fx_strength_level'):
|
||||
fx_strength_level = klc.get_fx_strength_level()
|
||||
|
||||
# 尝试判断是否为强分型
|
||||
if hasattr(klc, 'is_strong_fx'):
|
||||
is_strong_fx = klc.is_strong_fx()
|
||||
|
||||
# 如果分型强度小于1,设为0
|
||||
if fx_strength < 1:
|
||||
fx_strength = 0
|
||||
|
||||
klc_fx_info.append({
|
||||
'time': klc.end_time,
|
||||
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
|
||||
'fx_type': str(klc.klc_fx_type).replace("Chan_KLC_FX.", ""),
|
||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||
'fx_strength': fx_strength, # 分型强度分数 (0-100)
|
||||
'fx_strength_level': fx_strength_level, # 分型强度等级 (极强/强/中等/弱/极弱)
|
||||
'is_strong_fx': is_strong_fx # 是否为强分型
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"处理KLC分型信息时出错: {e}")
|
||||
# 如果出错,仍然添加基本信息,但分型强度为0
|
||||
klc_fx_info.append({
|
||||
'time': klc.end_time,
|
||||
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
|
||||
'fx_type': str(klc.klc_fx_type).replace("Chan_KLC_FX.", ""),
|
||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||
'fx_strength': 0,
|
||||
'fx_strength_level': "",
|
||||
'is_strong_fx': False
|
||||
})
|
||||
|
||||
return {
|
||||
'klc_list': klc_list,
|
||||
@@ -766,5 +813,175 @@ def search_stock():
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)})
|
||||
|
||||
@app.route('/api/filter_stocks', methods=['POST'])
|
||||
def filter_stocks():
|
||||
"""筛选满足条件的A股股票"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
start_time = data.get('start_time')
|
||||
end_time = data.get('end_time')
|
||||
timeframe = data.get('timeframe', '1d')
|
||||
fx_strength_threshold = data.get('fx_strength_threshold', 1.0)
|
||||
|
||||
if not start_time or not end_time:
|
||||
return jsonify({'error': '开始时间和结束时间不能为空'})
|
||||
|
||||
# 获取所有A股股票列表,如果失败则使用热门股票作为备用
|
||||
stock_list = []
|
||||
data_source = ""
|
||||
try:
|
||||
print("正在获取完整股票列表...")
|
||||
stock_list = china_stock.get_stock_list()
|
||||
if stock_list and len(stock_list) > 0:
|
||||
print(f"成功获取完整股票列表: {len(stock_list)} 只股票")
|
||||
data_source = "完整股票列表"
|
||||
else:
|
||||
raise Exception("获取到的股票列表为空")
|
||||
except Exception as e:
|
||||
print(f"获取完整股票列表失败: {e}")
|
||||
print("使用热门股票列表作为备用...")
|
||||
try:
|
||||
popular_stocks = china_stock.get_popular_stocks()
|
||||
stock_list = [{'symbol': stock['symbol'], 'name': stock['name']} for stock in popular_stocks]
|
||||
print(f"使用热门股票列表: {len(stock_list)} 只股票")
|
||||
data_source = "热门股票列表"
|
||||
except Exception as e2:
|
||||
print(f"获取热门股票列表也失败: {e2}")
|
||||
# 检查是否是网络连接问题
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower() or "network" in str(e).lower():
|
||||
return jsonify({
|
||||
'error': '网络连接超时,无法获取股票数据。请检查网络连接后重试。',
|
||||
'error_type': 'network_error',
|
||||
'suggestion': '请确保网络连接正常,或稍后重试。'
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': f'无法获取股票列表: {str(e)}'})
|
||||
|
||||
if not stock_list:
|
||||
return jsonify({
|
||||
'error': '无法获取股票列表,请检查网络连接后重试',
|
||||
'error_type': 'network_error',
|
||||
'suggestion': '请确保网络连接正常,或稍后重试。'
|
||||
})
|
||||
|
||||
results = []
|
||||
processed_count = 0
|
||||
total_count = len(stock_list)
|
||||
failed_count = 0
|
||||
|
||||
print(f"开始筛选股票,总数: {total_count}, 时间范围: {start_time} 到 {end_time}, 周期: {timeframe}")
|
||||
|
||||
for stock in stock_list:
|
||||
try:
|
||||
symbol = stock['symbol']
|
||||
name = stock['name']
|
||||
processed_count += 1
|
||||
|
||||
# 每处理20只股票打印一次进度
|
||||
if processed_count % 20 == 0:
|
||||
print(f"已处理 {processed_count}/{total_count} 只股票,成功: {len(results)}, 失败: {failed_count}")
|
||||
|
||||
# 获取股票K线数据
|
||||
df = get_a_stock_kl_data(symbol, timeframe, start_time=start_time, end_time=end_time)
|
||||
|
||||
if df is None or len(df) < 3:
|
||||
failed_count += 1
|
||||
# 如果连续失败太多,可能是网络问题
|
||||
if failed_count > 10 and len(results) == 0:
|
||||
print(f"连续失败 {failed_count} 次,可能是网络问题")
|
||||
return jsonify({
|
||||
'error': '网络连接不稳定,无法获取股票数据。请检查网络连接后重试。',
|
||||
'error_type': 'network_error',
|
||||
'processed_count': processed_count,
|
||||
'failed_count': failed_count
|
||||
})
|
||||
continue
|
||||
|
||||
# 进行缠论分析
|
||||
analysis_result = analyze_chan(df)
|
||||
|
||||
if not analysis_result or 'klc_fx_info' not in analysis_result:
|
||||
continue
|
||||
|
||||
klc_fx_info = analysis_result['klc_fx_info']
|
||||
|
||||
# 检查最近2个KLC是否有满足条件的分型
|
||||
recent_klcs = klc_fx_info[-2:] if len(klc_fx_info) >= 2 else klc_fx_info
|
||||
|
||||
for klc_info in recent_klcs:
|
||||
fx_strength = klc_info.get('fx_strength', 0)
|
||||
fx_type = klc_info.get('fx_type', 'UNKNOWN')
|
||||
|
||||
# 检查是否满足条件:分型强度>=阈值 且 分型类型不为UNKNOWN
|
||||
if fx_strength >= fx_strength_threshold and fx_type != 'UNKNOWN':
|
||||
# 获取当前价格(最新收盘价)
|
||||
current_price = df['close'].iloc[-1] if len(df) > 0 else None
|
||||
fx_price = klc_info.get('price', 0)
|
||||
|
||||
# 计算涨跌幅
|
||||
change_percent = 0
|
||||
if current_price and fx_price and fx_price > 0:
|
||||
change_percent = ((current_price - fx_price) / fx_price) * 100
|
||||
|
||||
# 格式化分型类型显示
|
||||
fx_type_display = format_fx_type(fx_type)
|
||||
|
||||
results.append({
|
||||
'symbol': symbol,
|
||||
'name': name,
|
||||
'fx_time': klc_info.get('time', ''),
|
||||
'fx_type': fx_type_display,
|
||||
'fx_strength': fx_strength,
|
||||
'fx_price': fx_price,
|
||||
'current_price': current_price,
|
||||
'change_percent': change_percent
|
||||
})
|
||||
break # 找到一个满足条件的就跳出循环
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理股票 {symbol} 时出错: {str(e)}")
|
||||
failed_count += 1
|
||||
continue
|
||||
|
||||
print(f"筛选完成,共找到 {len(results)} 只满足条件的股票")
|
||||
|
||||
# 按分型强度降序排列
|
||||
results.sort(key=lambda x: x['fx_strength'], reverse=True)
|
||||
|
||||
return jsonify({
|
||||
'results': results,
|
||||
'total_processed': processed_count,
|
||||
'total_found': len(results),
|
||||
'failed_count': failed_count,
|
||||
'data_source': data_source,
|
||||
'message': f'使用{data_source}进行筛选,共处理{processed_count}只股票,找到{len(results)}只满足条件的股票'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"筛选股票时发生错误: {str(e)}")
|
||||
# 检查是否是网络连接问题
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower() or "network" in str(e).lower():
|
||||
return jsonify({
|
||||
'error': '网络连接超时,请检查网络连接后重试。',
|
||||
'error_type': 'network_error',
|
||||
'suggestion': '请确保网络连接正常,或稍后重试。'
|
||||
})
|
||||
else:
|
||||
return jsonify({'error': str(e)})
|
||||
|
||||
def format_fx_type(fx_type):
|
||||
"""格式化分型类型显示"""
|
||||
fx_type_map = {
|
||||
'TOP1': '顶分型1',
|
||||
'TOP2': '顶分型2',
|
||||
'TOP3': '顶分型3',
|
||||
'BOTTOM1': '底分型1',
|
||||
'BOTTOM2': '底分型2',
|
||||
'BOTTOM3': '底分型3',
|
||||
'TOP': '顶分型',
|
||||
'BOTTOM': '底分型'
|
||||
}
|
||||
return fx_type_map.get(fx_type, fx_type)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host='0.0.0.0', port=8123)
|
||||
Reference in New Issue
Block a user