调整py脚本
This commit is contained in:
@@ -53,7 +53,7 @@ def get_history_records(data_dirs):
|
|||||||
if not os.path.exists(d): continue
|
if not os.path.exists(d): continue
|
||||||
for f in os.listdir(d):
|
for f in os.listdir(d):
|
||||||
if f.endswith('.json') and f != 'stat_result.json':
|
if f.endswith('.json') and f != 'stat_result.json':
|
||||||
with open(os.path.join(d, f), 'r') as file:
|
with open(os.path.join(d, f), 'r', encoding='utf-8') as file:
|
||||||
try:
|
try:
|
||||||
content = json.load(file)
|
content = json.load(file)
|
||||||
if isinstance(content, list):
|
if isinstance(content, list):
|
||||||
@@ -109,6 +109,7 @@ if __name__ == "__main__":
|
|||||||
df = pd.DataFrame(all_records).drop_duplicates(subset=['id']).sort_values('time')
|
df = pd.DataFrame(all_records).drop_duplicates(subset=['id']).sort_values('time')
|
||||||
df['time'] = pd.to_datetime(df['time'])
|
df['time'] = pd.to_datetime(df['time'])
|
||||||
|
|
||||||
print(main(next_period_time, df))
|
result = main(next_period_time, df)
|
||||||
|
print(json.dumps(result, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,475 +0,0 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
import math
|
|
||||||
import pandas as pd
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
# 玩法1.2 赔率映射
|
|
||||||
SUM12_ODDS = {
|
|
||||||
3: 41.9, 4: 41.9, 18: 41.9, 19: 41.9,
|
|
||||||
5: 20.38, 6: 20.38, 16: 20.38, 17: 20.38,
|
|
||||||
7: 13.51, 8: 13.51, 14: 13.51, 15: 13.51,
|
|
||||||
9: 9.7, 10: 9.7, 12: 9.7, 13: 9.7,
|
|
||||||
11: 8.1
|
|
||||||
}
|
|
||||||
INIT_CONFIG = {
|
|
||||||
"INIT_GOLD": 100000, # 初始金币betting_predictions_final_500.json
|
|
||||||
"init_cost": 100000,
|
|
||||||
"stop_win": 1100000, # 本金止盈点
|
|
||||||
"stop_loss": 0
|
|
||||||
}
|
|
||||||
# 玩法1.1 赔率映射
|
|
||||||
SIZE_ODDS = {"冠亚大": 2.1, "冠亚小": 1.7}
|
|
||||||
ODD_EVEN_ODDS = {"冠亚单": 1.7, "冠亚双": 2.1}
|
|
||||||
NUM_DETAIL_ODDS = 1.9199
|
|
||||||
# 玩法2.1/2.2/3 固定赔率
|
|
||||||
RANK_GLH_ODDS = 1.9199 # 玩法2.2
|
|
||||||
NUM_POS_ODDS = 9.599 # 玩法3
|
|
||||||
|
|
||||||
|
|
||||||
# 定义工具函数:判断是否为NaN(兼容Python的None和math.nan)
|
|
||||||
def is_nan(val):
|
|
||||||
return val is None or (isinstance(val, float) and math.isnan(val))
|
|
||||||
|
|
||||||
|
|
||||||
def load_actual_data(actual_dir):
|
|
||||||
actual_records = []
|
|
||||||
if not os.path.exists(actual_dir):
|
|
||||||
return actual_records
|
|
||||||
|
|
||||||
# 处理可能的嵌套目录
|
|
||||||
target_dir = actual_dir
|
|
||||||
if 'data_test_dir' in os.listdir(actual_dir):
|
|
||||||
target_dir = os.path.join(actual_dir, 'data_test_dir')
|
|
||||||
|
|
||||||
for file in os.listdir(target_dir):
|
|
||||||
if file.endswith('.json') and file != 'stat_result.json':
|
|
||||||
with open(os.path.join(target_dir, file), 'r') as f:
|
|
||||||
try:
|
|
||||||
data = json.load(f)
|
|
||||||
actual_records.extend(data)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
return actual_records
|
|
||||||
|
|
||||||
# 1. 加载实际结果数据(示例:从JSON字符串加载,可替换为文件读取)
|
|
||||||
# with open("data_test_dir1/2026_1_17_data_test.json", "r", encoding="utf-8") as f:
|
|
||||||
# actual_data = json.load(f)
|
|
||||||
actual_data = load_actual_data("data_test_dir1")
|
|
||||||
def get_history_records(data_dirs):
|
|
||||||
all_records = []
|
|
||||||
for d in data_dirs:
|
|
||||||
if not os.path.exists(d): continue
|
|
||||||
for f in os.listdir(d):
|
|
||||||
if f.endswith('.json') and f != 'stat_result.json':
|
|
||||||
with open(os.path.join(d, f), 'r') as file:
|
|
||||||
try:
|
|
||||||
content = json.load(file)
|
|
||||||
if isinstance(content, list):
|
|
||||||
all_records.extend([item for item in content if isinstance(item, dict)])
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
return all_records
|
|
||||||
# with open("data_test_predict/betting_predictions_final_2026-01-11.json", "r", encoding="utf-8") as f:
|
|
||||||
# with open("data_test_predict/betting_predictions_final_502.json", "r", encoding="utf-8") as f:
|
|
||||||
# with open("data_test_predict/betting_predictions_final_501.json", "r", encoding="utf-8") as f:
|
|
||||||
# predict_data = json.load(f)
|
|
||||||
predict_data = load_actual_data("data_test_predict")
|
|
||||||
|
|
||||||
|
|
||||||
# 标准化时间函数
|
|
||||||
def standardize_time(time_str):
|
|
||||||
try:
|
|
||||||
dt = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
|
|
||||||
return dt
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# 构建实际数据的时间映射(使用datetime对象作为key)
|
|
||||||
actual_time_map = {}
|
|
||||||
for item in actual_data:
|
|
||||||
std_dt = standardize_time(item["time"])
|
|
||||||
if std_dt:
|
|
||||||
actual_time_map[std_dt] = item
|
|
||||||
|
|
||||||
|
|
||||||
# 定义函数:获取时间所属的区间key(07:05:00 ~ 次日06:00:00)
|
|
||||||
def get_time_interval_key(dt):
|
|
||||||
# 确定区间起始时间:如果当前时间 >= 07:05:00,起始为当天07:05,否则为前一天07:05
|
|
||||||
start_hour, start_min = 7, 5
|
|
||||||
if dt.hour > start_hour or (dt.hour == start_hour and dt.minute >= start_min):
|
|
||||||
interval_start = datetime(dt.year, dt.month, dt.day, start_hour, start_min, 0)
|
|
||||||
else:
|
|
||||||
interval_start = datetime(dt.year, dt.month, dt.day, start_hour, start_min, 0) - timedelta(days=1)
|
|
||||||
# 区间结束时间:起始时间 + 1天 - 1小时5分钟(即次日06:00:00)
|
|
||||||
interval_end = interval_start + timedelta(days=1) - timedelta(hours=1, minutes=5)
|
|
||||||
|
|
||||||
# 格式化区间key
|
|
||||||
key = f"{interval_start.strftime('%Y-%m-%d %H:%M:%S')}_{interval_end.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
||||||
return key, interval_start, interval_end
|
|
||||||
|
|
||||||
|
|
||||||
# ====================== 定义输赢计算函数 ======================
|
|
||||||
def calculate_bet_result(actual, predict):
|
|
||||||
bet_result = {
|
|
||||||
"predict_id": predict["id"],
|
|
||||||
"time": predict["time"],
|
|
||||||
"actual_id": actual["id"],
|
|
||||||
"result_bet": [], # 数字排列押注结果
|
|
||||||
"result_detail_bet": [], # 数字排列大小单双押注结果
|
|
||||||
"winner_bet": [], # 冠亚和押注结果
|
|
||||||
"GD1_bet": [], # 冠亚大小押注结果
|
|
||||||
"GD2_bet": [], # 冠亚单双押注结果
|
|
||||||
"GLH_bet": [], # 龙虎押注结果
|
|
||||||
"total_profit": 0, # 总盈利
|
|
||||||
"total_cost": 0 # 总投入
|
|
||||||
}
|
|
||||||
|
|
||||||
# 3.1 计算result(数字排列)押注输赢
|
|
||||||
actual_result = actual["result"]
|
|
||||||
for idx, predict_idx_result in predict["result"].items():
|
|
||||||
_idx = int(idx)
|
|
||||||
hit = False
|
|
||||||
total_bet = 0
|
|
||||||
profit = 0
|
|
||||||
for predict_idx, bet in predict_idx_result.items():
|
|
||||||
if is_nan(bet):
|
|
||||||
continue
|
|
||||||
total_bet += bet
|
|
||||||
if actual_result[_idx] == int(predict_idx):
|
|
||||||
hit = True
|
|
||||||
profit += bet * NUM_POS_ODDS
|
|
||||||
bet_result["result_bet"].append({
|
|
||||||
"num": actual_result[_idx],
|
|
||||||
"bet": total_bet,
|
|
||||||
"hit": hit,
|
|
||||||
"profit": profit,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.1.1 计算各位置的大小单双
|
|
||||||
for idx, predict_detail_result in predict["result_detail"].items():
|
|
||||||
_idx = int(idx)
|
|
||||||
bet = 0
|
|
||||||
profit = 0
|
|
||||||
big_or_small = "大" if actual_result[_idx] >= 6 else "小"
|
|
||||||
single_or_double = "单" if (actual_result[_idx] & 1) == 1 else "双"
|
|
||||||
|
|
||||||
profit1 = predict_detail_result[big_or_small]
|
|
||||||
profit2 = predict_detail_result[single_or_double]
|
|
||||||
bet1 = predict_detail_result["小"]
|
|
||||||
bet2 = predict_detail_result["大"]
|
|
||||||
bet3 = predict_detail_result["双"]
|
|
||||||
bet4 = predict_detail_result["单"]
|
|
||||||
bet += (0 if is_nan(bet1) else bet1) + (0 if is_nan(bet2) else bet2) + (0 if is_nan(bet3) else bet3) + (
|
|
||||||
0 if is_nan(bet4) else bet4)
|
|
||||||
profit += (0 if is_nan(profit1) else profit1 * NUM_DETAIL_ODDS) + (
|
|
||||||
0 if is_nan(profit2) else profit2 * NUM_DETAIL_ODDS)
|
|
||||||
bet_result["result_detail_bet"].append({
|
|
||||||
"num": actual_result[_idx],
|
|
||||||
"bet": bet,
|
|
||||||
"hit": True if profit > 0 else False,
|
|
||||||
"profit": profit,
|
|
||||||
"big_or_small": big_or_small,
|
|
||||||
"single_or_double": single_or_double,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.2 计算winner(冠亚和)押注输赢
|
|
||||||
actual_winner = actual["winner"]
|
|
||||||
for winner_str, bet in predict["winner"].items():
|
|
||||||
if is_nan(bet):
|
|
||||||
continue
|
|
||||||
winner_val = int(winner_str)
|
|
||||||
hit = winner_val == actual_winner
|
|
||||||
profit = bet * (SUM12_ODDS[winner_val] if hit else 0)
|
|
||||||
bet_result["winner_bet"].append({
|
|
||||||
"winner_val": winner_val,
|
|
||||||
"bet": 0 if is_nan(bet) else bet,
|
|
||||||
"hit": hit,
|
|
||||||
"profit": profit,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.3 计算GD1(冠亚大小)押注输赢
|
|
||||||
actual_gd1 = actual["GD1"]
|
|
||||||
for gd1_type, bet in predict["GD1"].items():
|
|
||||||
if is_nan(bet):
|
|
||||||
continue
|
|
||||||
|
|
||||||
hit = gd1_type == actual_gd1
|
|
||||||
profit = bet * (SIZE_ODDS[actual_gd1] if hit else 0)
|
|
||||||
bet_result["GD1_bet"].append({
|
|
||||||
"gd1_type": gd1_type,
|
|
||||||
"bet": 0 if is_nan(bet) else bet,
|
|
||||||
"hit": hit,
|
|
||||||
"profit": profit,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.4 计算GD2(冠亚单双)押注输赢
|
|
||||||
actual_gd2 = actual["GD2"]
|
|
||||||
for gd2_type, bet in predict["GD2"].items():
|
|
||||||
if is_nan(bet):
|
|
||||||
continue
|
|
||||||
|
|
||||||
hit = gd2_type == actual_gd2
|
|
||||||
profit = bet * (ODD_EVEN_ODDS[gd2_type] if hit else 0)
|
|
||||||
bet_result["GD2_bet"].append({
|
|
||||||
"gd2_type": gd2_type,
|
|
||||||
"bet": 0 if is_nan(bet) else bet,
|
|
||||||
"hit": hit,
|
|
||||||
"profit": profit,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.5 计算GLH(龙虎)押注输赢
|
|
||||||
actual_glh = actual["GLH_result"]
|
|
||||||
for glh_type, bet in predict["GLH_result"].items():
|
|
||||||
idx = int(glh_type[4])
|
|
||||||
if idx >= len(actual_glh):
|
|
||||||
break
|
|
||||||
if is_nan(bet):
|
|
||||||
continue
|
|
||||||
glh_type = glh_type[-1:]
|
|
||||||
hit = glh_type == actual_glh[idx]
|
|
||||||
profit = bet * (RANK_GLH_ODDS if hit else 0)
|
|
||||||
bet_result["GLH_bet"].append({
|
|
||||||
"position": idx,
|
|
||||||
"glh_type": glh_type,
|
|
||||||
"bet": 0 if is_nan(bet) else bet,
|
|
||||||
"hit": hit,
|
|
||||||
"profit": profit,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 3.6 计算本轮总盈利
|
|
||||||
total_profit = sum([
|
|
||||||
sum(item["profit"] for item in bet_result["result_bet"]),
|
|
||||||
sum(item["profit"] for item in bet_result["result_detail_bet"]),
|
|
||||||
sum(item["profit"] for item in bet_result["winner_bet"]),
|
|
||||||
sum(item["profit"] for item in bet_result["GD1_bet"]),
|
|
||||||
sum(item["profit"] for item in bet_result["GD2_bet"]),
|
|
||||||
sum(item["profit"] for item in bet_result["GLH_bet"])
|
|
||||||
])
|
|
||||||
bet_result["total_profit"] = round(total_profit, 6) # 保留6位小数
|
|
||||||
|
|
||||||
# 3.7 计算本轮总投入
|
|
||||||
total_cost = sum([
|
|
||||||
sum(item["bet"] for item in bet_result["result_bet"]),
|
|
||||||
sum(item["bet"] for item in bet_result["result_detail_bet"]),
|
|
||||||
sum(item["bet"] for item in bet_result["winner_bet"]),
|
|
||||||
sum(item["bet"] for item in bet_result["GD1_bet"]),
|
|
||||||
sum(item["bet"] for item in bet_result["GD2_bet"]),
|
|
||||||
sum(item["bet"] for item in bet_result["GLH_bet"])
|
|
||||||
])
|
|
||||||
bet_result["total_cost"] = round(total_cost, 6)
|
|
||||||
|
|
||||||
return bet_result
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_bet_input_cost(bet_result):
|
|
||||||
this_round_total_cost = bet_result["total_cost"]
|
|
||||||
this_round_total_profit = bet_result["total_profit"]
|
|
||||||
|
|
||||||
global INIT_CONFIG
|
|
||||||
INIT_CONFIG["init_cost"] = INIT_CONFIG["init_cost"] - this_round_total_cost + this_round_total_profit
|
|
||||||
|
|
||||||
if INIT_CONFIG["init_cost"] <= INIT_CONFIG["stop_loss"] or INIT_CONFIG["init_cost"] >= INIT_CONFIG["stop_win"]:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
# ====================== 初始化区间聚合字典 ======================
|
|
||||||
interval_agg_data = {}
|
|
||||||
|
|
||||||
# 定义玩法列表(用于聚合)
|
|
||||||
PLAY_TYPES = [
|
|
||||||
"result_bet", # 数字排列
|
|
||||||
"result_detail_bet", # 数字排列大小单双
|
|
||||||
"winner_bet", # 冠亚和
|
|
||||||
"GD1_bet", # 冠亚大小
|
|
||||||
"GD2_bet", # 冠亚单双
|
|
||||||
"GLH_bet" # 龙虎
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# 初始化单个区间的聚合结构
|
|
||||||
def init_interval_agg():
|
|
||||||
agg = {
|
|
||||||
# 各玩法的聚合数据
|
|
||||||
"play_details": {
|
|
||||||
play_type: {
|
|
||||||
"total_input": 0.0, # 总投入
|
|
||||||
"total_income": 0.0, # 总收益
|
|
||||||
"input_income_ratio": 0.0, # 投入/收益比例
|
|
||||||
"profit": 0.0 # 利润(收益-投入)
|
|
||||||
} for play_type in PLAY_TYPES
|
|
||||||
},
|
|
||||||
# 整体聚合数据
|
|
||||||
"total": {
|
|
||||||
"total_input": 0.0,
|
|
||||||
"total_income": 0.0,
|
|
||||||
"input_income_ratio": 0.0,
|
|
||||||
"total_profit": 0.0 # 总利润(总收益-总投入)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return agg
|
|
||||||
|
|
||||||
|
|
||||||
# ====================== 批量匹配并计算结果 ======================
|
|
||||||
final_results = []
|
|
||||||
for predict_item in predict_data:
|
|
||||||
# 标准化预测时间
|
|
||||||
predict_time_str = predict_item["time"]
|
|
||||||
predict_dt = standardize_time(predict_time_str)
|
|
||||||
if not predict_dt:
|
|
||||||
final_results.append({
|
|
||||||
"predict_id": predict_item["id"],
|
|
||||||
"time": predict_time_str,
|
|
||||||
"error": "时间格式错误,无法解析"
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 获取所属区间key
|
|
||||||
interval_key, _, _ = get_time_interval_key(predict_dt)
|
|
||||||
|
|
||||||
# 按时间匹配实际结果
|
|
||||||
actual_item = actual_time_map.get(predict_dt)
|
|
||||||
if not actual_item:
|
|
||||||
final_results.append({
|
|
||||||
"predict_id": predict_item["id"],
|
|
||||||
"time": predict_time_str,
|
|
||||||
"error": "未找到对应时间的实际结果"
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 计算单条输赢结果
|
|
||||||
bet_result = calculate_bet_result(actual_item, predict_item)
|
|
||||||
_continue = calculate_bet_input_cost(bet_result)
|
|
||||||
final_results.append(bet_result)
|
|
||||||
|
|
||||||
# ====================== 聚合到对应时间区间 ======================
|
|
||||||
# 初始化区间数据(如果不存在)
|
|
||||||
if interval_key not in interval_agg_data:
|
|
||||||
interval_agg_data[interval_key] = init_interval_agg()
|
|
||||||
|
|
||||||
# 遍历每个玩法,聚合数据
|
|
||||||
total_input = 0.0
|
|
||||||
total_income = 0.0
|
|
||||||
for play_type in PLAY_TYPES:
|
|
||||||
# 计算该玩法的总投入和总收益
|
|
||||||
play_input = sum(item["bet"] for item in bet_result[play_type])
|
|
||||||
play_income = sum(item["profit"] for item in bet_result[play_type])
|
|
||||||
|
|
||||||
# 更新玩法详情
|
|
||||||
play_detail = interval_agg_data[interval_key]["play_details"][play_type]
|
|
||||||
play_detail["total_input"] += play_input
|
|
||||||
play_detail["total_income"] += play_income
|
|
||||||
# 计算利润
|
|
||||||
play_detail["profit"] = round(play_detail["total_income"] - play_detail["total_input"], 6)
|
|
||||||
# 计算投入/收益比例(避免除以0)
|
|
||||||
if play_detail["total_income"] != 0:
|
|
||||||
play_detail["input_income_ratio"] = round(play_detail["total_input"] / play_detail["total_income"], 6)
|
|
||||||
else:
|
|
||||||
play_detail["input_income_ratio"] = 0.0
|
|
||||||
|
|
||||||
# 累加至总投入/总收益
|
|
||||||
total_input += play_input
|
|
||||||
total_income += play_income
|
|
||||||
|
|
||||||
# 更新区间整体数据
|
|
||||||
total_detail = interval_agg_data[interval_key]["total"]
|
|
||||||
total_detail["total_input"] += total_input
|
|
||||||
total_detail["total_income"] += total_income
|
|
||||||
# 总利润(收益-投入)
|
|
||||||
total_detail["total_profit"] = round(total_detail["total_income"] - total_detail["total_input"], 6)
|
|
||||||
# 总投入/收益比例
|
|
||||||
if total_detail["total_income"] != 0:
|
|
||||||
total_detail["input_income_ratio"] = round(total_detail["total_input"] / total_detail["total_income"], 6)
|
|
||||||
else:
|
|
||||||
total_detail["input_income_ratio"] = 0.0
|
|
||||||
|
|
||||||
if not _continue:
|
|
||||||
break
|
|
||||||
|
|
||||||
# ====================== 输出区间聚合结果 ======================
|
|
||||||
print("=" * 100)
|
|
||||||
print("时间区间聚合盈亏统计")
|
|
||||||
print("=" * 100)
|
|
||||||
|
|
||||||
for interval_key, agg_data in interval_agg_data.items():
|
|
||||||
print(f"\n【区间】: {interval_key}")
|
|
||||||
print("-" * 80)
|
|
||||||
|
|
||||||
# 输出各玩法详情
|
|
||||||
print("【各玩法统计】:")
|
|
||||||
for play_type, play_data in agg_data["play_details"].items():
|
|
||||||
print(f"\n{play_type}:")
|
|
||||||
print(f" 总投入: {play_data['total_input']:.6f} 元")
|
|
||||||
print(f" 总收益: {play_data['total_income']:.6f} 元")
|
|
||||||
print(f" 投入/收益比例: {play_data['input_income_ratio']:.6f}")
|
|
||||||
print(f" 利润(收益-投入): {play_data['profit']:.6f} 元")
|
|
||||||
|
|
||||||
# 输出整体统计
|
|
||||||
print("\n【区间整体统计】:")
|
|
||||||
total_data = agg_data["total"]
|
|
||||||
print(f" 总投入: {total_data['total_input']:.6f} 元")
|
|
||||||
print(f" 总收益: {total_data['total_income']:.6f} 元")
|
|
||||||
print(f" 投入/收益比例: {total_data['input_income_ratio']:.6f}")
|
|
||||||
print(f" 总利润(收益-投入): {total_data['total_profit']:.6f} 元")
|
|
||||||
print("-" * 80)
|
|
||||||
|
|
||||||
# ====================== 输出原始明细(可选) ======================
|
|
||||||
print("\n\n" + "=" * 100)
|
|
||||||
print("原始押注明细")
|
|
||||||
print("=" * 100)
|
|
||||||
for res in final_results:
|
|
||||||
if "error" in res:
|
|
||||||
print(f"【预测ID: {res['predict_id']}】 时间: {res['time']} | 错误: {res['error']}\n")
|
|
||||||
continue
|
|
||||||
|
|
||||||
print(f"===== 预测ID: {res['predict_id']} | 时间: {res['time']} | 实际ID: {res['actual_id']} =====")
|
|
||||||
|
|
||||||
# 输出数字排列押注结果
|
|
||||||
print("\n--- 数字排列押注 ---")
|
|
||||||
for item in res["result_bet"]:
|
|
||||||
status = "命中" if item["hit"] else "未命中"
|
|
||||||
print(f"数字{item['num']} | 押注{item['bet']}元 | {status} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
# 输出数字排列大小单双押注结果
|
|
||||||
print("\n--- 数字排列大小单双押注 ---")
|
|
||||||
for item in res["result_detail_bet"]:
|
|
||||||
single_or_double = item["single_or_double"]
|
|
||||||
big_or_small = item["big_or_small"]
|
|
||||||
print(f"数字{item['num']} | 押注{item['bet']}元 | {single_or_double}{big_or_small} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
# 输出冠亚和押注结果
|
|
||||||
print("\n--- 冠亚和押注 ---")
|
|
||||||
for item in res["winner_bet"]:
|
|
||||||
status = "命中" if item["hit"] else "未命中"
|
|
||||||
print(f"冠亚和{item['winner_val']} | 押注{item['bet']}元 | {status} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
# 输出冠亚大小押注结果
|
|
||||||
print("\n--- 冠亚大小押注 ---")
|
|
||||||
for item in res["GD1_bet"]:
|
|
||||||
status = "命中" if item["hit"] else "未命中"
|
|
||||||
print(f"{item['gd1_type']} | 押注{item['bet']}元 | {status} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
# 输出冠亚单双押注结果
|
|
||||||
print("\n--- 冠亚单双押注 ---")
|
|
||||||
for item in res["GD2_bet"]:
|
|
||||||
status = "命中" if item["hit"] else "未命中"
|
|
||||||
print(f"{item['gd2_type']} | 押注{item['bet']}元 | {status} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
# 输出龙虎押注结果
|
|
||||||
print("\n--- 龙虎押注 ---")
|
|
||||||
for item in res["GLH_bet"]:
|
|
||||||
status = "命中" if item["hit"] else "未命中"
|
|
||||||
print(f"位置{item['position']}({item['glh_type']}) | 押注{item['bet']}元 | {status} | 盈利{item['profit']}元")
|
|
||||||
|
|
||||||
print("\n" + "-" * 80 + "\n")
|
|
||||||
|
|
||||||
total_input = sum([current_input["total"]["total_input"] for _, current_input in interval_agg_data.items()])
|
|
||||||
total_income = sum([current_input["total"]["total_income"] for _, current_input in interval_agg_data.items()])
|
|
||||||
print(f"总投入 {total_input}, 总收益 {total_income}, 最终盈利: {total_income - total_input:.6f}")
|
|
||||||
|
|
||||||
# 可选:将区间聚合结果保存为JSON文件
|
|
||||||
with open("interval_agg_result_1_1_2.json", "w", encoding="utf-8") as f:
|
|
||||||
json.dump(interval_agg_data, f, ensure_ascii=False, indent=4)
|
|
||||||
print("\n区间聚合结果已保存至 interval_agg_result.json")
|
|
||||||
@@ -14,8 +14,8 @@ public class BocaiApplication {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext context = SpringApplication.run(BocaiApplication.class, args);
|
ApplicationContext context = SpringApplication.run(BocaiApplication.class, args);
|
||||||
|
|
||||||
BetSchedule betSchedule = context.getBean(BetSchedule.class);
|
// BetSchedule betSchedule = context.getBean(BetSchedule.class);
|
||||||
betSchedule.placeBet();
|
// betSchedule.placeBet();
|
||||||
|
|
||||||
// // 依次执行三个任务
|
// // 依次执行三个任务
|
||||||
//
|
//
|
||||||
@@ -24,20 +24,10 @@ public class BocaiApplication {
|
|||||||
// CrawlerSchedule crawlerSchedule = context.getBean(CrawlerSchedule.class);
|
// CrawlerSchedule crawlerSchedule = context.getBean(CrawlerSchedule.class);
|
||||||
// crawlerSchedule.executeLotteryDraw();
|
// crawlerSchedule.executeLotteryDraw();
|
||||||
//
|
//
|
||||||
// // 2. 执行ExAggregateDataScriptSchedule方法
|
// 3. 执行ExBetScriptSchedule方法
|
||||||
// System.out.println("\n=== 开始执行ExAggregateDataScriptSchedule任务 ===");
|
System.out.println("\n=== 开始执行ExBetScriptSchedule任务 ===");
|
||||||
// ExAggregateDataScriptSchedule exAggregateDataScriptSchedule = context.getBean(ExAggregateDataScriptSchedule.class);
|
ExBetScriptSchedule exBetScriptSchedule = context.getBean(ExBetScriptSchedule.class);
|
||||||
// exAggregateDataScriptSchedule.executePythonScript();
|
exBetScriptSchedule.executePythonScript();
|
||||||
//
|
|
||||||
// // 3. 执行ExBetScriptSchedule方法
|
|
||||||
// System.out.println("\n=== 开始执行ExBetScriptSchedule任务 ===");
|
|
||||||
// ExBetScriptSchedule exBetScriptSchedule = context.getBean(ExBetScriptSchedule.class);
|
|
||||||
// exBetScriptSchedule.executePythonScript();
|
|
||||||
//
|
|
||||||
// // 4. 执行GenBetRecordSchedule方法
|
|
||||||
// System.out.println("\n=== 开始执行GenBetRecordSchedule任务 ===");
|
|
||||||
// GenBetRecordSchedule genBetRecordSchedule = context.getBean(GenBetRecordSchedule.class);
|
|
||||||
// genBetRecordSchedule.processBetPredictions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ public class BetSchedule {
|
|||||||
private BetRecordRepository betRecordRepository;
|
private BetRecordRepository betRecordRepository;
|
||||||
|
|
||||||
// 每天早上7.07分开始,每5分钟执行一次到第二天早上6点结束(7:07, 7:12, 7:17...23:57, 0:02, 0:07...5:57)
|
// 每天早上7.07分开始,每5分钟执行一次到第二天早上6点结束(7:07, 7:12, 7:17...23:57, 0:02, 0:07...5:57)
|
||||||
@Scheduled(cron = "0 7/5 7-23,0-6 * * ?")
|
// @Scheduled(cron = "0 7/5 7-23,0-6 * * ?")
|
||||||
public void placeBet() {
|
public void placeBet() {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
int hour = now.getHour();
|
int hour = now.getHour();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class CrawlerSchedule {
|
|||||||
// 每天凌晨2点执行爬取开奖结果
|
// 每天凌晨2点执行爬取开奖结果
|
||||||
//@Scheduled(cron = "0 0 2 * * ?")
|
//@Scheduled(cron = "0 0 2 * * ?")
|
||||||
// 每7秒执行一次爬取开奖结果
|
// 每7秒执行一次爬取开奖结果
|
||||||
@Scheduled(cron = "*/9 * * * * ?")
|
// @Scheduled(cron = "*/9 * * * * ?")
|
||||||
/*@Scheduled(cron = "0 6-59/5 7-23 * * ?")
|
/*@Scheduled(cron = "0 6-59/5 7-23 * * ?")
|
||||||
@Scheduled(cron = "0 0-55/5 0-6 * * ?")*/
|
@Scheduled(cron = "0 0-55/5 0-6 * * ?")*/
|
||||||
public void executeLotteryDraw() {
|
public void executeLotteryDraw() {
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
package com.tem.bocai.schedules;
|
|
||||||
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行统计脚本
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ExAggregateDataScriptSchedule {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理文件路径,确保路径正确
|
|
||||||
* @param filePath 文件路径
|
|
||||||
* @return 处理后的文件路径
|
|
||||||
*/
|
|
||||||
private String handleFilePath(String filePath) {
|
|
||||||
// 处理路径分隔符,统一使用系统默认分隔符
|
|
||||||
filePath = filePath.replace("/", System.getProperty("file.separator"));
|
|
||||||
filePath = filePath.replace("\\", System.getProperty("file.separator"));
|
|
||||||
|
|
||||||
// 如果路径包含空格,确保路径被正确处理
|
|
||||||
// Runtime.exec会自动处理带空格的路径,不需要手动添加引号
|
|
||||||
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
ExAggregateDataScriptSchedule schedule = new ExAggregateDataScriptSchedule();
|
|
||||||
schedule.executePythonScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 每天凌晨2点执行
|
|
||||||
// @Scheduled(cron = "0 10 6 * * ?")
|
|
||||||
public void executePythonScript() {
|
|
||||||
System.out.println("开始执行Python脚本...");
|
|
||||||
|
|
||||||
// 执行aggregate_data_v7.py脚本,不需要参数
|
|
||||||
String[] params = {};
|
|
||||||
executePythonScriptWithParams("aggregate_data_v7.py", params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行带参数的Python脚本
|
|
||||||
* @param scriptPath Python脚本路径
|
|
||||||
* @param params 脚本参数数组(可以包含文件路径)
|
|
||||||
*/
|
|
||||||
public void executePythonScriptWithParams(String scriptPath, String[] params) {
|
|
||||||
try {
|
|
||||||
// 处理脚本路径,确保路径正确
|
|
||||||
scriptPath = handleFilePath(scriptPath);
|
|
||||||
|
|
||||||
// 构建命令数组
|
|
||||||
String[] command = new String[params.length + 2];
|
|
||||||
command[0] = "python";
|
|
||||||
command[1] = scriptPath;
|
|
||||||
|
|
||||||
// 添加参数,处理文件路径参数
|
|
||||||
for (int i = 0; i < params.length; i++) {
|
|
||||||
// 检查参数是否为文件路径(包含路径分隔符)
|
|
||||||
if (params[i].contains("\\") || params[i].contains("/")) {
|
|
||||||
command[i + 2] = handleFilePath(params[i]);
|
|
||||||
} else {
|
|
||||||
command[i + 2] = params[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("执行命令: " + String.join(" ", command));
|
|
||||||
|
|
||||||
// 创建ProcessBuilder并设置工作目录为PyModel
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(command);
|
|
||||||
// 获取项目根目录的绝对路径
|
|
||||||
String projectRoot = System.getProperty("user.dir");
|
|
||||||
// 设置工作目录为PyModel的绝对路径
|
|
||||||
java.io.File pyModelDir = new java.io.File(projectRoot, "PyModel");
|
|
||||||
pb.directory(pyModelDir);
|
|
||||||
System.out.println("执行目录: " + pyModelDir.getAbsolutePath());
|
|
||||||
|
|
||||||
// 执行Python脚本
|
|
||||||
Process process = pb.start();
|
|
||||||
|
|
||||||
// 读取脚本输出
|
|
||||||
BufferedReader reader = new BufferedReader(
|
|
||||||
new InputStreamReader(process.getInputStream(), "UTF-8")
|
|
||||||
);
|
|
||||||
|
|
||||||
String line;
|
|
||||||
StringBuilder output = new StringBuilder();
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
output.append(line).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取错误输出
|
|
||||||
BufferedReader errorReader = new BufferedReader(
|
|
||||||
new InputStreamReader(process.getErrorStream(), "UTF-8")
|
|
||||||
);
|
|
||||||
|
|
||||||
StringBuilder errorOutput = new StringBuilder();
|
|
||||||
while ((line = errorReader.readLine()) != null) {
|
|
||||||
errorOutput.append(line).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待脚本执行完成
|
|
||||||
int exitCode = process.waitFor();
|
|
||||||
|
|
||||||
System.out.println("Python脚本执行完成,退出码: " + exitCode);
|
|
||||||
System.out.println("脚本输出:\n" + output.toString());
|
|
||||||
|
|
||||||
if (exitCode != 0) {
|
|
||||||
System.err.println("脚本执行错误:\n" + errorOutput.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
System.err.println("执行Python脚本时发生错误:");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,23 @@
|
|||||||
package com.tem.bocai.schedules;
|
package com.tem.bocai.schedules;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.json.JSONArray;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.tem.bocai.entity.BetRecord;
|
||||||
|
import com.tem.bocai.repository.BetRecordRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行预测脚本
|
* 执行预测脚本
|
||||||
@@ -13,6 +25,9 @@ import java.io.InputStreamReader;
|
|||||||
@Component
|
@Component
|
||||||
public class ExBetScriptSchedule {
|
public class ExBetScriptSchedule {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BetRecordRepository betRecordRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理文件路径,确保路径正确
|
* 处理文件路径,确保路径正确
|
||||||
* @param filePath 文件路径
|
* @param filePath 文件路径
|
||||||
@@ -34,14 +49,19 @@ public class ExBetScriptSchedule {
|
|||||||
schedule.executePythonScript();
|
schedule.executePythonScript();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每天凌晨2点执行
|
// 每分钟执行一次
|
||||||
// @Scheduled(cron = "0 10 6 * * ?")
|
@Scheduled(cron = "0 * * * * ?")
|
||||||
public void executePythonScript() {
|
public void executePythonScript() {
|
||||||
System.out.println("开始执行Python脚本...");
|
System.out.println("开始执行Python脚本...");
|
||||||
|
|
||||||
// 执行aggregate_data_v7.py脚本,不需要参数
|
// 获取当前时间,格式化为yyyy-MM-dd HH:mm:ss
|
||||||
String[] params = {};
|
String currentTime = java.time.LocalDateTime.now().format(
|
||||||
executePythonScriptWithParams("batch_predict_betting_v7.py", params);
|
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||||
|
);
|
||||||
|
|
||||||
|
// 执行batch_predict_betting_v8.py脚本,添加当前时间作为参数
|
||||||
|
String[] params = {"--next_period_time", currentTime};
|
||||||
|
executePythonScriptWithParams("batch_predict_betting_v8.py", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,6 +128,8 @@ public class ExBetScriptSchedule {
|
|||||||
|
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
System.err.println("脚本执行错误:\n" + errorOutput.toString());
|
System.err.println("脚本执行错误:\n" + errorOutput.toString());
|
||||||
|
} else {
|
||||||
|
parseScriptOutput(output.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
@@ -115,4 +137,161 @@ public class ExBetScriptSchedule {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析脚本输出,提取result字段中值不为None的数据
|
||||||
|
* @param output 脚本输出
|
||||||
|
*/
|
||||||
|
private void parseScriptOutput(String output) {
|
||||||
|
try {
|
||||||
|
System.out.println("开始解析脚本输出...");
|
||||||
|
JSONObject jsonOutput = JSON.parseObject(output);
|
||||||
|
if (jsonOutput == null) {
|
||||||
|
System.out.println("输出为空或无法解析为JSON");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject result = jsonOutput.getJSONObject("result");
|
||||||
|
if (result == null) {
|
||||||
|
System.out.println("未找到result字段");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Map<Integer, Object>> validResults = new HashMap<>();
|
||||||
|
|
||||||
|
for (String key : result.keySet()) {
|
||||||
|
int pos = Integer.parseInt(key);
|
||||||
|
JSONObject posResult = result.getJSONObject(key);
|
||||||
|
|
||||||
|
Map<Integer, Object> validNums = new HashMap<>();
|
||||||
|
|
||||||
|
for (String numKey : posResult.keySet()) {
|
||||||
|
Object value = posResult.get(numKey);
|
||||||
|
if (value != null && !value.toString().equals("null") && !value.toString().equals("None")) {
|
||||||
|
validNums.put(Integer.parseInt(numKey), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validNums.isEmpty()) {
|
||||||
|
validResults.put(pos, validNums);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!validResults.isEmpty()) {
|
||||||
|
System.out.println("提取到的有效预测结果:");
|
||||||
|
for (Map.Entry<Integer, Map<Integer, Object>> entry : validResults.entrySet()) {
|
||||||
|
System.out.println("位置 " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成符合test.json格式的数据
|
||||||
|
generateOutputData(validResults);
|
||||||
|
} else {
|
||||||
|
System.out.println("未找到有效的预测结果(所有值均为None)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("解析脚本输出时发生错误:");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成符合test.json格式的数据
|
||||||
|
*/
|
||||||
|
private void generateOutputData(Map<Integer, Map<Integer, Object>> validResults) {
|
||||||
|
org.json.JSONObject outputData = new org.json.JSONObject();
|
||||||
|
|
||||||
|
// 设置固定字段
|
||||||
|
outputData.put("lottery", "SGFT");
|
||||||
|
|
||||||
|
// 生成drawNumber: 年月日+001-288
|
||||||
|
String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
|
||||||
|
// 计算期数:从00:00:00起每5分钟为一期,获取当前时间当前期数
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
int hour = now.getHour();
|
||||||
|
int minute = now.getMinute();
|
||||||
|
|
||||||
|
int totalMinutes = hour * 60 + minute;
|
||||||
|
int period = (totalMinutes / 5) + 1;
|
||||||
|
|
||||||
|
// 确保期数在有效范围内
|
||||||
|
if (period < 1) {
|
||||||
|
period = 1;
|
||||||
|
} else if (period > 288) {
|
||||||
|
period = 288;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化期数为3位数字
|
||||||
|
String periodStr = String.format("%03d", period);
|
||||||
|
String drawNumber = dateStr + periodStr;
|
||||||
|
outputData.put("drawNumber", drawNumber);
|
||||||
|
|
||||||
|
// 生成bets数组
|
||||||
|
org.json.JSONArray betsArray = new org.json.JSONArray();
|
||||||
|
|
||||||
|
// 位置标题映射
|
||||||
|
String[] titles = {"冠军", "亚军", "季军", "第四名", "第五名", "第六名", "第七名", "第八名", "第九名", "第十名"};
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Map<Integer, Object>> posEntry : validResults.entrySet()) {
|
||||||
|
int pos = posEntry.getKey();
|
||||||
|
Map<Integer, Object> numsMap = posEntry.getValue();
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Object> numEntry : numsMap.entrySet()) {
|
||||||
|
int num = numEntry.getKey();
|
||||||
|
Object value = numEntry.getValue();
|
||||||
|
|
||||||
|
if (value != null && !"null".equals(value.toString())) {
|
||||||
|
org.json.JSONObject betObject = new org.json.JSONObject();
|
||||||
|
|
||||||
|
// 生成game字段: "B" + 位置
|
||||||
|
betObject.put("game", "B" + (pos + 1));
|
||||||
|
|
||||||
|
// 设置投注内容
|
||||||
|
betObject.put("contents", String.valueOf(num));
|
||||||
|
|
||||||
|
// 设置固定字段
|
||||||
|
betObject.put("amount", 1);
|
||||||
|
betObject.put("odds", 9.599);
|
||||||
|
|
||||||
|
// 设置标题
|
||||||
|
if (pos >= 0 && pos < titles.length) {
|
||||||
|
betObject.put("title", titles[pos]);
|
||||||
|
} else {
|
||||||
|
betObject.put("title", "位置" + (pos + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
betsArray.put(betObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputData.put("bets", betsArray);
|
||||||
|
outputData.put("fastBets", false);
|
||||||
|
outputData.put("ignore", false);
|
||||||
|
|
||||||
|
System.out.println("生成的输出数据:");
|
||||||
|
System.out.println(outputData.toString(2));
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
try {
|
||||||
|
// 创建BetRecord对象
|
||||||
|
BetRecord betRecord = new BetRecord();
|
||||||
|
betRecord.setBetTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
betRecord.setBetData(outputData.toString());
|
||||||
|
betRecord.setCreateTime(new Date());
|
||||||
|
betRecord.setUpdateTime(new Date());
|
||||||
|
betRecord.setBetNum(drawNumber);
|
||||||
|
|
||||||
|
// 检查betNum是否已存在,避免重复保存
|
||||||
|
if (!betRecordRepository.existsByBetNum(drawNumber)) {
|
||||||
|
betRecordRepository.save(betRecord);
|
||||||
|
System.out.println("保存投注记录到数据库成功,期数: " + drawNumber);
|
||||||
|
} else {
|
||||||
|
System.out.println("投注记录已存在,期数: " + drawNumber);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("保存投注记录到数据库失败:");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
package com.tem.bocai.schedules;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.tem.bocai.entity.BetRecord;
|
|
||||||
import com.tem.bocai.repository.BetRecordRepository;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.json.JSONTokener;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class GenBetRecordSchedule {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BetRecordRepository betRecordRepository;
|
|
||||||
|
|
||||||
// 静态变量,用于跟踪顺序序号
|
|
||||||
private static int seqCounter = 1;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
// 注意:直接运行此方法会导致betRecordRepository为null
|
|
||||||
// 请通过BocaiApplication的main方法运行,或使用Spring Boot启动
|
|
||||||
System.out.println("请通过BocaiApplication的main方法运行,或使用Spring Boot启动");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 每天6:30执行
|
|
||||||
// @Scheduled(cron = "0 30 6 * * ?")
|
|
||||||
public void processBetPredictions() {
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
String currentTime = now.format(
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
|
||||||
);
|
|
||||||
System.out.println(currentTime + " - 开始处理投注预测数据...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 删除所有旧数据
|
|
||||||
betRecordRepository.deleteAll();
|
|
||||||
System.out.println(" - 已删除所有旧数据");
|
|
||||||
|
|
||||||
// 读取投注预测数据
|
|
||||||
JSONArray betDataArray = readBetDataFromJson();
|
|
||||||
System.out.println(" - 成功读取投注预测数据,共" + betDataArray.length() + "条记录");
|
|
||||||
|
|
||||||
// 处理每条投注预测数据
|
|
||||||
for (int i = 0; i < betDataArray.length(); i++) {
|
|
||||||
JSONObject betData = betDataArray.getJSONObject(i);
|
|
||||||
String time = betData.getString("time");
|
|
||||||
System.out.println(" - 处理投注时间: " + time);
|
|
||||||
|
|
||||||
// 获取result中值不为null的对象
|
|
||||||
JSONObject result = betData.getJSONObject("result");
|
|
||||||
|
|
||||||
// 生成符合test.json格式的数据
|
|
||||||
JSONObject outputData = generateOutputData(betData, result);
|
|
||||||
|
|
||||||
// 打印处理结果
|
|
||||||
System.out.println(" - 生成的投注数据: " + outputData);
|
|
||||||
|
|
||||||
// 保存处理结果到数据库
|
|
||||||
saveToDatabase(outputData, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(currentTime + " - 投注预测数据处理完成");
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println(currentTime + " - 处理投注预测数据失败:");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成符合test.json格式的数据
|
|
||||||
*/
|
|
||||||
private JSONObject generateOutputData(JSONObject betData, JSONObject result) {
|
|
||||||
JSONObject outputData = new JSONObject();
|
|
||||||
|
|
||||||
// 设置固定字段
|
|
||||||
outputData.put("lottery", "SGFT");
|
|
||||||
|
|
||||||
// 生成drawNumber: 年月日+001-288
|
|
||||||
String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
|
||||||
|
|
||||||
// 确保seqCounter在1-288之间循环
|
|
||||||
if (seqCounter > 288) {
|
|
||||||
seqCounter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用顺序序号
|
|
||||||
String seqStr = String.format("%03d", seqCounter);
|
|
||||||
String drawNumber = dateStr + seqStr;
|
|
||||||
|
|
||||||
// 序号自增
|
|
||||||
seqCounter++;
|
|
||||||
|
|
||||||
outputData.put("drawNumber", drawNumber);
|
|
||||||
|
|
||||||
// 生成bets数组
|
|
||||||
JSONArray betsArray = new JSONArray();
|
|
||||||
|
|
||||||
// 位置标题映射
|
|
||||||
String[] titles = {"冠军", "亚军", "季军", "第四名", "第五名", "第六名", "第七名", "第八名", "第九名", "第十名"};
|
|
||||||
|
|
||||||
for (String pos : result.keySet()) {
|
|
||||||
JSONObject posData = result.getJSONObject(pos);
|
|
||||||
for (String num : posData.keySet()) {
|
|
||||||
Object value = posData.get(num);
|
|
||||||
if (value != null && !"null".equals(value.toString())) {
|
|
||||||
JSONObject betObject = new JSONObject();
|
|
||||||
|
|
||||||
// 生成game字段: "B" + 位置
|
|
||||||
int position = Integer.parseInt(pos);
|
|
||||||
betObject.put("game", "B" + (position + 1));
|
|
||||||
|
|
||||||
// 设置投注内容
|
|
||||||
betObject.put("contents", num);
|
|
||||||
|
|
||||||
// 设置固定字段
|
|
||||||
betObject.put("amount", 1);
|
|
||||||
betObject.put("odds", 9.599);
|
|
||||||
|
|
||||||
// 设置标题
|
|
||||||
if (position >= 0 && position < titles.length) {
|
|
||||||
betObject.put("title", titles[position]);
|
|
||||||
} else {
|
|
||||||
betObject.put("title", "位置" + (position + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
betsArray.put(betObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputData.put("bets", betsArray);
|
|
||||||
outputData.put("fastBets", false);
|
|
||||||
outputData.put("ignore", false);
|
|
||||||
|
|
||||||
return outputData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从json文件中读取投注预测数据
|
|
||||||
*/
|
|
||||||
private JSONArray readBetDataFromJson() throws IOException {
|
|
||||||
// 使用绝对路径读取文件
|
|
||||||
String projectRoot = System.getProperty("user.dir");
|
|
||||||
String filePath = projectRoot + "/PyModel/data_test_predict/betting_predictions_final_1_20.json";
|
|
||||||
System.out.println(" - 读取投注预测数据文件: " + filePath);
|
|
||||||
|
|
||||||
FileReader reader = new FileReader(filePath);
|
|
||||||
JSONTokener tokener = new JSONTokener(reader);
|
|
||||||
JSONArray betData = new JSONArray(tokener);
|
|
||||||
reader.close();
|
|
||||||
return betData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存有效投注结果到文件
|
|
||||||
*/
|
|
||||||
private void saveValidResults(JSONObject validResults, String time) throws IOException {
|
|
||||||
// 使用绝对路径保存文件
|
|
||||||
String projectRoot = System.getProperty("user.dir");
|
|
||||||
String filePath = projectRoot + "/PyModel/bet_output_" + time.replace(":", "-") + ".json";
|
|
||||||
System.out.println(" - 保存有效投注结果到文件: " + filePath);
|
|
||||||
|
|
||||||
FileWriter writer = new FileWriter(filePath);
|
|
||||||
writer.write(validResults.toString(2)); // 格式化输出,缩进2个空格
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存有效投注结果到数据库
|
|
||||||
*/
|
|
||||||
private void saveToDatabase(JSONObject validResults, String time) {
|
|
||||||
try {
|
|
||||||
// 从validResults中获取drawNumber作为betNum
|
|
||||||
String drawNumber = validResults.getString("drawNumber");
|
|
||||||
|
|
||||||
// 检查betNum是否已存在
|
|
||||||
if (betRecordRepository.existsByBetNum(drawNumber)) {
|
|
||||||
System.out.println(" - 投注编号已存在,跳过保存: " + drawNumber);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建BetRecord实体
|
|
||||||
BetRecord betRecord = new BetRecord();
|
|
||||||
betRecord.setBetTime(time);
|
|
||||||
betRecord.setBetData(validResults.toString());
|
|
||||||
betRecord.setBetNum(drawNumber);
|
|
||||||
betRecord.setCreateTime(new Date());
|
|
||||||
betRecord.setUpdateTime(new Date());
|
|
||||||
|
|
||||||
// 保存到数据库
|
|
||||||
BetRecord savedRecord = betRecordRepository.save(betRecord);
|
|
||||||
System.out.println(" - 保存有效投注结果到数据库,ID: " + savedRecord.getId() + ", 投注编号: " + drawNumber);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println(" - 保存有效投注结果到数据库失败: " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user