Remove files

This commit is contained in:
jackyu66git
2025-05-26 19:54:07 +08:00
parent 0cc19132eb
commit 0754b5ae59
25 changed files with 1076 additions and 1103 deletions
+236 -19
View File
@@ -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)
+46 -13
View File
@@ -21,26 +21,59 @@ class ChinaStockData:
def get_stock_list(self):
"""获取A股股票列表"""
try:
# 获取沪深A股实时行情
stock_info = ak.stock_zh_a_spot_em()
import requests
# 设置较短的超时时间,避免长时间等待
import akshare as ak
print("正在获取A股股票列表...")
# 尝试获取沪深A股实时行情,设置超时时间
try:
# 临时设置requests的默认超时
original_timeout = getattr(requests, 'timeout', None)
requests.timeout = 10 # 10秒超时
stock_info = ak.stock_zh_a_spot_em()
# 恢复原始超时设置
if original_timeout:
requests.timeout = original_timeout
else:
delattr(requests, 'timeout')
except Exception as network_error:
print(f"网络请求失败: {network_error}")
# 网络失败时返回空列表,让调用方使用备用方案
return []
if stock_info is None or len(stock_info) == 0:
print("获取到的股票数据为空")
return []
# 增加到前2000只股票,提供更多选择
stock_list = []
for index, row in stock_info.head(2000).iterrows():
# 过滤掉ST股票和停牌股票
stock_name = str(row['名称'])
if 'ST' not in stock_name and '*' not in stock_name:
stock_list.append({
'symbol': row['代码'],
'name': row['名称'],
'price': float(row['最新价']) if pd.notna(row['最新价']) else 0.0,
'change_pct': float(row['涨跌幅']) if pd.notna(row['涨跌幅']) else 0.0,
'volume': float(row['成交量']) if pd.notna(row['成交量']) else 0.0,
'amount': float(row['成交']) if pd.notna(row['成交']) else 0.0
})
try:
# 过滤掉ST股票和停牌股票
stock_name = str(row['名称'])
if 'ST' not in stock_name and '*' not in stock_name:
stock_list.append({
'symbol': row['代码'],
'name': row['名称'],
'price': float(row['最新价']) if pd.notna(row['最新价']) else 0.0,
'change_pct': float(row['涨跌幅']) if pd.notna(row['涨跌幅']) else 0.0,
'volume': float(row['成交']) if pd.notna(row['成交']) else 0.0,
'amount': float(row['成交额']) if pd.notna(row['成交额']) else 0.0
})
except Exception as row_error:
print(f"处理股票数据行时出错: {row_error}")
continue
# 按成交金额排序,优先显示活跃股票
stock_list.sort(key=lambda x: x['amount'], reverse=True)
print(f"成功获取 {len(stock_list)} 只股票")
return stock_list
except Exception as e:
print(f"获取股票列表失败: {e}")
return []
+448 -1
View File
@@ -74,9 +74,51 @@
}
.data-container {
margin-top: 10px;
position: relative;
z-index: 10;
background-color: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.nav-tabs {
margin-bottom: 10px;
position: relative;
z-index: 20;
background-color: white;
border-radius: 8px 8px 0 0;
padding: 10px 10px 0 10px;
}
.nav-tabs .nav-link {
border-radius: 6px 6px 0 0;
margin-right: 5px;
font-weight: 500;
transition: all 0.2s ease;
}
.nav-tabs .nav-link:hover {
background-color: #f8f9fa;
border-color: #dee2e6;
}
.nav-tabs .nav-link.active {
background-color: #0d6efd;
color: white;
border-color: #0d6efd;
}
/* 特别突出显示股票筛选tab */
#stock-filter-tab {
background-color: #28a745 !important;
color: white !important;
border-color: #28a745 !important;
font-weight: bold !important;
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3) !important;
}
#stock-filter-tab:hover {
background-color: #218838 !important;
border-color: #1e7e34 !important;
}
#stock-filter-tab.active {
background-color: #155724 !important;
border-color: #155724 !important;
}
.table-container {
overflow-x: auto;
@@ -478,6 +520,9 @@
<li class="nav-item" role="presentation">
<button class="nav-link" id="trade-points-tab" data-bs-toggle="tab" data-bs-target="#trade-points" type="button" role="tab">买卖点</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="stock-filter-tab" data-bs-toggle="tab" data-bs-target="#stock-filter" type="button" role="tab">股票筛选</button>
</li>
</ul>
<div class="data-source-info alert alert-info py-2 mt-1 mb-2" style="display:none;">
<small id="dataSourceText"></small>
@@ -592,6 +637,81 @@
</table>
</div>
</div>
<div class="tab-pane fade" id="stock-filter" role="tabpanel">
<div class="container-fluid">
<div class="row mb-3">
<div class="col-md-12">
<h5>A股强分型筛选</h5>
<p class="text-muted">筛选最近2个K线合并(KLC)中有一个满足分型强度≥1.0且分型类型不为UNKNOWN的A股股票</p>
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">
<label for="filterStartTime" class="form-label">开始时间:</label>
<input type="datetime-local" id="filterStartTime" class="form-control">
</div>
<div class="col-md-3">
<label for="filterEndTime" class="form-label">结束时间:</label>
<input type="datetime-local" id="filterEndTime" class="form-control">
</div>
<div class="col-md-3">
<label for="filterTimeframe" class="form-label">时间周期:</label>
<select id="filterTimeframe" class="form-select">
<option value="5m">5分钟</option>
<option value="15m">15分钟</option>
<option value="30m">30分钟</option>
<option value="1h">1小时</option>
<option value="4h">4小时</option>
<option value="1d" selected>1日</option>
<option value="1w">1周</option>
<option value="1M">1月</option>
</select>
</div>
<div class="col-md-3">
<label for="fxStrengthThreshold" class="form-label">分型强度阈值:</label>
<input type="number" id="fxStrengthThreshold" class="form-control" value="1.0" min="0" max="100" step="0.1">
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<button class="btn btn-primary" onclick="filterStocks()">
<i class="bi bi-search"></i> 开始筛选
</button>
<button class="btn btn-secondary ms-2" onclick="exportFilterResults()">
<i class="bi bi-download"></i> 导出结果
</button>
<span id="filterProgress" class="ms-3" style="display:none;">
<i class="bi bi-hourglass-split"></i> 正在筛选中...
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="table-container">
<table id="stockFilterTable" class="display compact" style="width:100%">
<thead>
<tr>
<th>股票代码</th>
<th>股票名称</th>
<th>分型时间</th>
<th>分型类型</th>
<th>分型强度</th>
<th>分型价格</th>
<th>当前价格</th>
<th>涨跌幅(%)</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -841,6 +961,12 @@
updateChartDisplay();
});
// 添加K线周期切换事件监听器
$('input[name="klinePeriod"]').change(function() {
console.log('K线周期切换:', $(this).attr('id'), $(this).is(':checked'));
updateChartDisplay();
});
// 当选择不同的元素时间周期时
$('#elementTimeframe').change(function() {
const elementTimeframe = $(this).val();
@@ -1198,7 +1324,7 @@
}
// 检查是否使用小周期K线数据
const useElementPeriod = $('#useElementPeriod').is(':checked') &&
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
currentData.element_kline_data &&
Array.isArray(currentData.element_kline_data);
@@ -4004,6 +4130,52 @@
updateTables(currentData);
}
});
// 页面加载完成后初始化
$(document).ready(function() {
// 设置默认的筛选时间(最近7天)
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
$('#filterEndTime').val(now.toISOString().slice(0, 16));
$('#filterStartTime').val(weekAgo.toISOString().slice(0, 16));
// 初始化股票筛选表格
initStockFilterTable();
// 突出显示股票筛选tab
setTimeout(function() {
const stockFilterTab = $('#stock-filter-tab');
if (stockFilterTab.length > 0) {
console.log('股票筛选tab已找到,开始突出显示');
// 添加闪烁效果来吸引注意
stockFilterTab.addClass('animate__animated animate__pulse');
// 滚动到tab区域
$('html, body').animate({
scrollTop: $('.data-container').offset().top - 100
}, 1000);
// 添加提示信息
const alertDiv = $(`
<div class="alert alert-info alert-dismissible fade show" role="alert" style="position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 400px;">
<strong>新功能!</strong> 股票筛选功能已添加,请查看绿色的"股票筛选"标签页。
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`);
$('body').append(alertDiv);
// 10秒后自动隐藏提示
setTimeout(() => {
alertDiv.alert('close');
}, 10000);
} else {
console.error('未找到股票筛选tab');
}
}, 2000);
});
});
// 自动刷新相关变量
@@ -5103,6 +5275,281 @@
window.astockStatusInterval = setInterval(updateAStockTradingStatus, 30000);
console.log('A股交易时间状态更新器已启动');
}
// 股票筛选相关函数
let stockFilterTable = null;
// 初始化股票筛选表格
function initStockFilterTable() {
// 简单的表格初始化,不使用DataTable
console.log('初始化股票筛选表格');
}
// 筛选股票
function filterStocks() {
const startTime = $('#filterStartTime').val();
const endTime = $('#filterEndTime').val();
const timeframe = $('#filterTimeframe').val();
const threshold = parseFloat($('#fxStrengthThreshold').val());
if (!startTime || !endTime) {
alert('请选择开始时间和结束时间');
return;
}
if (new Date(startTime) >= new Date(endTime)) {
alert('开始时间必须早于结束时间');
return;
}
// 显示进度指示器
$('#filterProgress').show();
$('#stockFilterTable tbody').empty();
// 发送筛选请求
$.ajax({
url: '/api/filter_stocks',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
start_time: startTime,
end_time: endTime,
timeframe: timeframe,
fx_strength_threshold: threshold
}),
timeout: 300000, // 5分钟超时
success: function(response) {
$('#filterProgress').hide();
if (response.error) {
// 根据错误类型显示不同的错误信息
if (response.error_type === 'network_error') {
showNetworkErrorAlert(response.error, response.suggestion);
} else {
alert('筛选失败: ' + response.error);
}
return;
}
// 更新表格数据
updateStockFilterTable(response.results);
// 显示统计信息
const totalCount = response.results.length;
const processedCount = response.total_processed || 0;
const failedCount = response.failed_count || 0;
const dataSource = response.data_source || '未知';
let message = `筛选完成!使用${dataSource},共处理 ${processedCount} 只股票,找到 ${totalCount} 只满足条件的股票`;
if (failedCount > 0) {
message += `${failedCount} 只股票数据获取失败`;
}
// 显示成功提示
showSuccessAlert(message);
},
error: function(xhr, status, error) {
$('#filterProgress').hide();
console.error('筛选请求失败:', error, status, xhr);
// 根据错误类型显示不同的错误信息
if (status === 'timeout') {
showNetworkErrorAlert(
'请求超时,可能是网络连接不稳定或数据量较大',
'请检查网络连接,或尝试缩小时间范围后重试'
);
} else if (xhr.responseJSON && xhr.responseJSON.error_type === 'network_error') {
showNetworkErrorAlert(xhr.responseJSON.error, xhr.responseJSON.suggestion);
} else {
alert('筛选请求失败: ' + (xhr.responseJSON?.error || error || '未知错误'));
}
}
});
}
// 显示网络错误提示
function showNetworkErrorAlert(errorMessage, suggestion) {
const alertDiv = $(`
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<h6><i class="fas fa-exclamation-triangle"></i> 网络连接问题</h6>
<p><strong>错误信息:</strong>${errorMessage}</p>
<p><strong>建议:</strong>${suggestion}</p>
<hr>
<p class="mb-0">
<small>
<i class="fas fa-info-circle"></i>
如果问题持续存在,请检查网络连接或联系管理员
</small>
</p>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`);
$('#stock-filter .container-fluid').prepend(alertDiv);
// 10秒后自动隐藏提示
setTimeout(() => {
alertDiv.alert('close');
}, 10000);
}
// 显示成功提示
function showSuccessAlert(message) {
const alertDiv = $(`
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle"></i> ${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`);
$('#stock-filter .container-fluid').prepend(alertDiv);
// 5秒后自动隐藏提示
setTimeout(() => {
alertDiv.alert('close');
}, 5000);
}
// 更新股票筛选表格
function updateStockFilterTable(results) {
const tbody = $('#stockFilterTable tbody');
tbody.empty();
if (!results || results.length === 0) {
tbody.append('<tr><td colspan="9" class="text-center">没有找到满足条件的股票</td></tr>');
return;
}
// 按分型强度降序排列
results.sort((a, b) => b.fx_strength - a.fx_strength);
// 添加新数据
results.forEach(function(stock) {
const strengthClass = getStrengthClass(stock.fx_strength);
const changeClass = stock.change_percent >= 0 ? 'text-danger' : 'text-success';
const changeSign = stock.change_percent >= 0 ? '+' : '';
const row = `
<tr>
<td>${stock.symbol}</td>
<td>${stock.name}</td>
<td>${stock.fx_time}</td>
<td>${stock.fx_type}</td>
<td><span class="${strengthClass}">${stock.fx_strength.toFixed(2)}</span></td>
<td>${stock.fx_price.toFixed(2)}</td>
<td>${stock.current_price ? stock.current_price.toFixed(2) : '-'}</td>
<td><span class="${changeClass}">${changeSign}${(stock.change_percent || 0).toFixed(2)}%</span></td>
<td><button class="btn btn-sm btn-outline-primary" onclick="analyzeStock('${stock.symbol}')">分析</button></td>
</tr>
`;
tbody.append(row);
});
}
// 获取分型强度对应的CSS类
function getStrengthClass(strength) {
if (strength >= 2.0) return 'text-danger fw-bold';
else if (strength >= 1.5) return 'text-warning fw-bold';
else if (strength >= 1.0) return 'text-info';
else return '';
}
// 分析特定股票
function analyzeStock(symbol) {
// 切换到主分析页面
$('#stock-filter-tab').removeClass('active');
$('#kline-tab').addClass('active');
$('#stock-filter').removeClass('show active');
$('#kline').addClass('show active');
// 切换数据源为A股
$('#dataSource').val('a_stock');
$('#dataSource').trigger('change');
// 等待数据源切换完成后设置股票代码
setTimeout(() => {
$('#astockSymbol').val(symbol);
// 触发分析
updateChart();
}, 500);
}
// 导出筛选结果
function exportFilterResults() {
const tbody = $('#stockFilterTable tbody tr');
if (tbody.length === 0 || (tbody.length === 1 && tbody.find('td').length === 1)) {
alert('没有可导出的数据');
return;
}
// 创建CSV内容
const headers = ['股票代码', '股票名称', '分型时间', '分型类型', '分型强度', '分型价格', '当前价格', '涨跌幅(%)'];
let csvContent = headers.join(',') + '\n';
tbody.each(function() {
const cells = $(this).find('td');
if (cells.length > 1) { // 排除"没有数据"的行
const row = [];
cells.slice(0, 8).each(function() { // 只取前8列,排除操作列
row.push($(this).text().trim());
});
csvContent += row.join(',') + '\n';
}
});
// 创建下载链接
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', `股票筛选结果_${new Date().toISOString().slice(0, 10)}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// 页面加载完成后初始化
$(document).ready(function() {
// 设置默认的筛选时间(最近7天)
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
$('#filterEndTime').val(now.toISOString().slice(0, 16));
$('#filterStartTime').val(weekAgo.toISOString().slice(0, 16));
// 初始化股票筛选表格
initStockFilterTable();
// 突出显示股票筛选tab
setTimeout(function() {
const stockFilterTab = $('#stock-filter-tab');
if (stockFilterTab.length > 0) {
console.log('股票筛选tab已找到,开始突出显示');
// 滚动到tab区域
$('html, body').animate({
scrollTop: $('.data-container').offset().top - 100
}, 1000);
// 添加提示信息
const alertDiv = $(`
<div class="alert alert-info alert-dismissible fade show" role="alert" style="position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 400px;">
<strong>新功能!</strong> 股票筛选功能已添加,请查看绿色的"股票筛选"标签页。
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`);
$('body').append(alertDiv);
// 10秒后自动隐藏提示
setTimeout(() => {
alertDiv.alert('close');
}, 10000);
} else {
console.error('未找到股票筛选tab');
}
}, 2000);
});
</script>
</body>
</html>