/// <summary> /// 获得Qp相关的组合,只针对PLC_CNT=3的情况 /// </summary> /// <param name="comb"></param> /// <param name="index"></param> /// <returns></returns> private static int[] getQpRelationIndice(common.Math.Combination comb, int index) { if (comb.M != 2) { return(null); } int[] c = comb.Combine(index); List <int> ret = new List <int>(); ret.Add(index); for (int i = 0; i < comb.N; i++) { if (Array.IndexOf(c, i) == -1) { ret.Add(comb.Index(new int[] { i, c[0] })); ret.Add(comb.Index(new int[] { i, c[1] })); } } return(ret.ToArray()); }
private void handle(string filename) { RaceData race = RaceData.Load(filename); if (race.Count < 2) { return; } long tp = race.First().Key; if (tp - race.Skip(1).First().Key != 300000) { return; } RaceDataItem item = race.First().Value; RaceDataItem item2 = race.Skip(1).First().Value; if (item.Odds.E == 0 || item2.Odds.E == 0) { return; } double[] p1, p3, pq_win, pq_plc; Fitting.calcProbility(item2.Odds, out p1, out p3, out pq_win, out pq_plc); // 计算预计概率与当前赔率下下注比例的交叉熵 double[] q1, qq; double r1, rq; q1 = Fitting.calcBetRateForWin(item.Odds, out r1); qq = Fitting.calcBetRateForQn(item.Odds, out rq); double E = cross_entropy(p1, q1) + cross_entropy(pq_win, qq); // 当前赔率下交叉熵过大则退出,不下单 if (E > item2.Odds.E * E_THRESHOLD_SCALE) { this.Invoke(new MethodInvoker(delegate { this.txtLog.AppendText(string.Format("{0:HH:mm:ss} > file {1} 变化过于剧烈{2}/{3}\r\n", DateTime.Now, filename, E, item2.Odds.E)); })); return; } List <InvestRecordWp> wp_records = new List <InvestRecordWp>(); for (int i = 0; i < item.Odds.Count; i++) { Hrs h = item.Odds[i]; double sp_w_min = Math.Min(h.Win, item2.Odds[i].Win); double sp_w_max = Math.Max(h.Win, item2.Odds[i].Win); double sp_p_min = Math.Min(h.Plc, item2.Odds[i].Plc); double sp_p_max = Math.Max(h.Plc, item2.Odds[i].Plc); // For Bet { WaterWPList vlist = item.Waters.GetWpEatWater(h.No).GetValuableWater(MIN_R, sp_w_min, p1[i], sp_p_min, p3[i]); double bet_amount_win = 0, bet_amount_plc = 0; bool full_win = false, full_plc = false; foreach (WaterWPItem w in vlist.OrderBy(x => x.Percent)) { if (w.WinAmount > 0 && full_win) { continue; } if (w.PlcAmount > 0 && full_plc) { continue; } double bet_amount = -1; if (w.WinAmount > 0) { double O = Math.Min(w.WinLimit / LIMIT_SCALE, sp_w_min) * 100 / w.Percent; double max_bet = (T * Math.Pow(O * p1[i] - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * p1[i] * (1 - p1[i])); if (bet_amount_win >= max_bet) { full_win = true; continue; } else { bet_amount = Math.Min(max_bet - bet_amount_win, w.WinAmount); } } if (w.PlcAmount > 0) { double O = Math.Min(w.PlcLimit / LIMIT_SCALE, sp_p_min) * 100 / w.Percent; double max_bet = (T * Math.Pow(O * p3[i] - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * p3[i] * (1 - p3[i])); if (bet_amount_plc >= max_bet) { full_plc = true; continue; } else { if (bet_amount == -1) { bet_amount = Math.Min(max_bet - bet_amount_plc, w.PlcAmount); } else { bet_amount = Math.Min(bet_amount, Math.Min(max_bet - bet_amount_plc, w.PlcAmount)); // 有Win也有Plc, 那么Plc肯定和Win一样 } } } if (bet_amount > 0) { bet_amount = Math.Round(bet_amount / WP_STEP) * WP_STEP; if (bet_amount > 0) { InvestRecordWp ir = new InvestRecordWp() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "BET", HorseNo = h.No, Percent = w.Percent, WinLimit = w.WinLimit, PlcLimit = w.PlcLimit, FittingLoss = item.Odds.E }; if (w.WinLimit > 0) { ir.WinAmount = bet_amount; ir.WinOdds = sp_w_min; ir.WinProbility = p1[i]; } if (w.PlcLimit > 0) { ir.PlcAmount = bet_amount; ir.PlcOdds = sp_p_min; ir.PlcProbility = p3[i]; } wp_records.Add(ir); bet_amount_win += ir.WinAmount; bet_amount_plc += ir.PlcAmount; } } } } // For Eat { WaterWPList vlist = item.Waters.GetWpBetWater(h.No).GetValuableWater(MIN_R, sp_w_max, p1[i], sp_p_max, p3[i]); double eat_amount_win = 0, eat_amount_plc = 0; bool full_win = false, full_plc = false; foreach (WaterWPItem w in vlist.OrderByDescending(x => x.Percent)) { if (w.WinAmount > 0 && full_win) { continue; } if (w.PlcAmount > 0 && full_plc) { continue; } double eat_amount = -1; if (w.WinAmount > 0) { double O = 1 + w.Percent / 100 / Math.Min(w.WinLimit / LIMIT_SCALE, sp_w_max); double max_eat = (T * Math.Pow(O * (1 - p1[i]) - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * (1 - p1[i]) * p1[i]); max_eat = max_eat / Math.Min(w.WinLimit / LIMIT_SCALE, sp_w_max); if (eat_amount_win >= max_eat) { full_win = true; continue; } else { eat_amount = Math.Min(max_eat - eat_amount_win, w.WinAmount); } } if (w.PlcAmount > 0) { double O = 1 + w.Percent / 100 / Math.Min(w.PlcLimit / LIMIT_SCALE, sp_p_max); double max_eat = (T * Math.Pow(O * (1 - p3[i]) - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * (1 - p3[i]) * p3[i]); max_eat = max_eat / Math.Min(w.PlcLimit / LIMIT_SCALE, sp_p_max); if (eat_amount_plc >= max_eat) { full_plc = true; continue; } else { if (eat_amount == -1) { eat_amount = Math.Min(max_eat - eat_amount_plc, w.PlcAmount); } else { eat_amount = Math.Min(eat_amount, Math.Min(max_eat - eat_amount_plc, w.PlcAmount)); } } } if (eat_amount > 0) { eat_amount = Math.Round(eat_amount / WP_STEP) * WP_STEP; if (eat_amount > 0) { InvestRecordWp ir = new InvestRecordWp() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "EAT", HorseNo = h.No, Percent = w.Percent, WinLimit = w.WinLimit, PlcLimit = w.PlcLimit, FittingLoss = item.Odds.E }; if (w.WinLimit > 0) { ir.WinAmount = eat_amount; ir.WinOdds = sp_w_max; ir.WinProbility = p1[i]; } if (w.PlcLimit > 0) { ir.PlcAmount = eat_amount; ir.PlcOdds = sp_p_max; ir.PlcProbility = p3[i]; } wp_records.Add(ir); eat_amount_win += ir.WinAmount; eat_amount_plc += ir.PlcAmount; } } } } } List <InvestRecordQn> qn_records = new List <InvestRecordQn>(); common.Math.Combination comb2 = new common.Math.Combination(item.Odds.Count, 2); int[][] combinations = comb2.GetCombinations(); for (int i = 0; i < combinations.Length; i++) { int[] c = combinations[i]; string horseNo = string.Format("{0}-{1}", item.Odds[c[0]].No, item.Odds[c[1]].No); if (pq_win != null) { double sp_min = Math.Min(item.Odds.SpQ[horseNo], item2.Odds.SpQ[horseNo]); double sp_max = Math.Max(item.Odds.SpQ[horseNo], item2.Odds.SpQ[horseNo]); // For Bet { WaterQnList vlist = item.Waters.GetQnEatWater(horseNo).GetValuableWater(MIN_R, sp_min, pq_win[i]); double bet_amount = 0; foreach (WaterQnItem w in vlist.OrderBy(x => x.Percent)) { double O = Math.Min(w.Limit / LIMIT_SCALE, sp_min) * 100 / w.Percent; double max_bet = (T * Math.Pow(O * pq_win[i] - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * pq_win[i] * (1 - pq_win[i])); if (bet_amount >= max_bet) { break; } double current_amount = Math.Min(max_bet - bet_amount, w.Amount); current_amount = Math.Round(current_amount / QN_STEP) * QN_STEP; if (current_amount > 0) { InvestRecordQn ir = new InvestRecordQn() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "BET", Type = "Q", HorseNo = horseNo, Percent = w.Percent, Amount = current_amount, Limit = w.Limit, Odds = sp_min, Probility = pq_win[i], FittingLoss = item.Odds.E }; qn_records.Add(ir); bet_amount += ir.Amount; } } } // For Eat { WaterQnList vlist = item.Waters.GetQnBetWater(horseNo).GetValuableWater(MIN_R, sp_max, pq_win[i]); double eat_amount = 0; foreach (WaterQnItem w in vlist.OrderByDescending(x => x.Percent)) { double O = 1 + w.Percent / 100 / Math.Min(w.Limit / LIMIT_SCALE, sp_max); double max_eat = (T * Math.Pow(O * (1 - pq_win[i]) - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * (1 - pq_win[i]) * pq_win[i]); max_eat = max_eat / Math.Min(w.Limit / LIMIT_SCALE, sp_max); if (eat_amount >= max_eat) { break; } double current_amount = Math.Min(max_eat - eat_amount, w.Amount); current_amount = Math.Round(current_amount / QN_STEP) * QN_STEP; if (current_amount > 0) { InvestRecordQn ir = new InvestRecordQn() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "EAT", Type = "Q", HorseNo = horseNo, Percent = w.Percent, Amount = current_amount, Limit = w.Limit, Odds = sp_max, Probility = pq_win[i], FittingLoss = item.Odds.E }; qn_records.Add(ir); eat_amount += ir.Amount; } } } } if (pq_plc != null) { double sp_min = Math.Min(item.Odds.SpQp[horseNo], item2.Odds.SpQp[horseNo]); double sp_max = Math.Max(item.Odds.SpQp[horseNo], item2.Odds.SpQp[horseNo]); // For Bet { WaterQnList vlist = item.Waters.GetQpEatWater(horseNo).GetValuableWater(MIN_R, sp_min, pq_plc[i]); double bet_amount = 0; foreach (WaterQnItem w in vlist.OrderBy(x => x.Percent)) { double O = Math.Min(w.Limit / LIMIT_SCALE, sp_min) * 100 / w.Percent; double max_bet = (T * Math.Pow(O * pq_plc[i] - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * pq_plc[i] * (1 - pq_plc[i])); if (bet_amount >= max_bet) { break; } double current_amount = Math.Min(max_bet - bet_amount, w.Amount); current_amount = Math.Round(current_amount / QN_STEP) * QN_STEP; if (current_amount > 0) { InvestRecordQn ir = new InvestRecordQn() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "BET", Type = "QP", HorseNo = horseNo, Percent = w.Percent, Amount = current_amount, Limit = w.Limit, Odds = sp_min, Probility = pq_plc[i], FittingLoss = item.Odds.E }; qn_records.Add(ir); bet_amount += ir.Amount; } } } // For Eat { WaterQnList vlist = item.Waters.GetQpBetWater(horseNo).GetValuableWater(MIN_R, sp_max, pq_win[i]); double eat_amount = 0; foreach (WaterQnItem w in vlist.OrderByDescending(x => x.Percent)) { double O = 1 + w.Percent / 100 / Math.Min(w.Limit / LIMIT_SCALE, sp_max); double max_eat = (T * Math.Pow(O * (1 - pq_plc[i]) - 1, 2)) / (LOSS_RATE_COEFFICIENT * Math.Pow(O, 2) * (1 - pq_plc[i]) * pq_plc[i]); max_eat = max_eat / Math.Min(w.Limit / LIMIT_SCALE, sp_max); if (eat_amount >= max_eat) { break; } double current_amount = Math.Min(max_eat - eat_amount, w.Amount); current_amount = Math.Round(current_amount / QN_STEP) * QN_STEP; if (current_amount > 0) { InvestRecordQn ir = new InvestRecordQn() { TimeKey = tp, Model = MODEL, CardID = race.CardID, RaceNo = race.RaceNo, Direction = "EAT", Type = "QP", HorseNo = horseNo, Percent = w.Percent, Amount = current_amount, Limit = w.Limit, Odds = sp_max, Probility = pq_plc[i], FittingLoss = item.Odds.E }; qn_records.Add(ir); eat_amount += ir.Amount; } } } } } using (MySqlConnection conn = new MySqlConnection("server=120.24.210.35;user id=hrsdata;password=abcd0000;database=hrsdata;port=3306;charset=utf8")) { conn.Open(); using (MySqlCommand cmd = new MySqlCommand(@" insert into sl_invest_wp (time_key,model,cd_id,rc_no,direction,hs_no,percent,w_limit,p_limit,rc_time,fitting_loss,w_amt,w_od,w_prob,p_amt,p_od,p_prob) values (?time_key,?model,?cd_id,?rc_no,?direction,?hs_no,?percent,?w_limit,?p_limit,?rc_time,?fitting_loss,?w_amt,?w_od,?w_prob,?p_amt,?p_od,?p_prob) on duplicate key update rc_time=?rc_time,fitting_loss=?fitting_loss,w_amt=?w_amt,w_od=?w_od,w_prob=?w_prob,p_amt=?p_amt,p_od=?p_od,p_prob=?p_prob,lmt=CURRENT_TIMESTAMP() ", conn)) { cmd.Parameters.Add("?time_key", MySqlDbType.Int64); cmd.Parameters.Add("?model", MySqlDbType.Int32); cmd.Parameters.Add("?cd_id", MySqlDbType.UInt64); cmd.Parameters.Add("?rc_no", MySqlDbType.Int32); cmd.Parameters.Add("?direction", MySqlDbType.VarChar, 10); cmd.Parameters.Add("?hs_no", MySqlDbType.Int32); cmd.Parameters.Add("?percent", MySqlDbType.Decimal); cmd.Parameters.Add("?w_limit", MySqlDbType.Decimal); cmd.Parameters.Add("?p_limit", MySqlDbType.Decimal); cmd.Parameters.Add("?rc_time", MySqlDbType.DateTime); cmd.Parameters.Add("?fitting_loss", MySqlDbType.Decimal); cmd.Parameters.Add("?w_amt", MySqlDbType.Decimal); cmd.Parameters.Add("?w_od", MySqlDbType.Decimal); cmd.Parameters.Add("?w_prob", MySqlDbType.Decimal); cmd.Parameters.Add("?p_amt", MySqlDbType.Decimal); cmd.Parameters.Add("?p_od", MySqlDbType.Decimal); cmd.Parameters.Add("?p_prob", MySqlDbType.Decimal); foreach (InvestRecordWp ir in wp_records) { cmd.Parameters["?time_key"].Value = ir.TimeKey; cmd.Parameters["?model"].Value = ir.Model; cmd.Parameters["?cd_id"].Value = ir.CardID; cmd.Parameters["?rc_no"].Value = ir.RaceNo; cmd.Parameters["?direction"].Value = ir.Direction; cmd.Parameters["?hs_no"].Value = int.Parse(ir.HorseNo); cmd.Parameters["?percent"].Value = ir.Percent; cmd.Parameters["?w_limit"].Value = ir.WinLimit; cmd.Parameters["?p_limit"].Value = ir.PlcLimit; cmd.Parameters["?rc_time"].Value = race.StartTime; cmd.Parameters["?fitting_loss"].Value = ir.FittingLoss; cmd.Parameters["?w_amt"].Value = ir.WinAmount; cmd.Parameters["?w_od"].Value = ir.WinOdds; cmd.Parameters["?w_prob"].Value = ir.WinProbility; cmd.Parameters["?p_amt"].Value = ir.PlcAmount; cmd.Parameters["?p_od"].Value = ir.PlcOdds; cmd.Parameters["?p_prob"].Value = ir.PlcProbility; cmd.ExecuteNonQuery(); } } using (MySqlCommand cmd = new MySqlCommand(@" insert into sl_invest_qn(time_key,model,cd_id,rc_no,direction,q_type,hs_no,percent,q_limit,rc_time,fitting_loss,amt,od,prob) values (?time_key,?model,?cd_id,?rc_no,?direction,?q_type,?hs_no,?percent,?q_limit,?rc_time,?fitting_loss,?amt,?od,?prob) on duplicate key update rc_time=?rc_time,fitting_loss=?fitting_loss,amt=?amt,od=?od,prob=?prob,lmt=CURRENT_TIMESTAMP() ", conn)) { cmd.Parameters.Add("?time_key", MySqlDbType.Int64); cmd.Parameters.Add("?model", MySqlDbType.Int32); cmd.Parameters.Add("?cd_id", MySqlDbType.UInt64); cmd.Parameters.Add("?rc_no", MySqlDbType.Int32); cmd.Parameters.Add("?direction", MySqlDbType.VarChar, 10); cmd.Parameters.Add("?q_type", MySqlDbType.VarChar, 10); cmd.Parameters.Add("?hs_no", MySqlDbType.VarChar, 20); cmd.Parameters.Add("?percent", MySqlDbType.Decimal); cmd.Parameters.Add("?q_limit", MySqlDbType.Decimal); cmd.Parameters.Add("?rc_time", MySqlDbType.DateTime); cmd.Parameters.Add("?fitting_loss", MySqlDbType.Decimal); cmd.Parameters.Add("?amt", MySqlDbType.Decimal); cmd.Parameters.Add("?od", MySqlDbType.Decimal); cmd.Parameters.Add("?prob", MySqlDbType.Decimal); foreach (InvestRecordQn ir in qn_records) { cmd.Parameters["?time_key"].Value = ir.TimeKey; cmd.Parameters["?model"].Value = ir.Model; cmd.Parameters["?cd_id"].Value = ir.CardID; cmd.Parameters["?rc_no"].Value = ir.RaceNo; cmd.Parameters["?direction"].Value = ir.Direction; cmd.Parameters["?q_type"].Value = ir.Type; cmd.Parameters["?hs_no"].Value = ir.HorseNo; cmd.Parameters["?percent"].Value = ir.Percent; cmd.Parameters["?q_limit"].Value = ir.Limit; cmd.Parameters["?rc_time"].Value = race.StartTime; cmd.Parameters["?fitting_loss"].Value = ir.FittingLoss; cmd.Parameters["?amt"].Value = ir.Amount; cmd.Parameters["?od"].Value = ir.Odds; cmd.Parameters["?prob"].Value = ir.Probility; cmd.ExecuteNonQuery(); } } } }
public static void calcProbility(double[] ee, double[] dd, int PLC_CNT, out double[] p1, out double[] p3, out double[] pq_win, out double[] pq_plc) { int CNT = ee.Length; p1 = new double[CNT]; p3 = new double[CNT]; // 需要计算各种组合细节 common.Math.Combination combq = new common.Math.Combination(CNT, 2); pq_win = new double[combq.Length]; pq_plc = new double[combq.Length]; common.Math.Combination comb_plc = new common.Math.Combination(CNT - 1, PLC_CNT - 1); int[][] _plc_combinations = comb_plc.GetCombinations(); common.Math.Combination comb2 = null; int[][] _2_combinations = null; if (PLC_CNT > 3) { comb2 = new common.Math.Combination(PLC_CNT - 1, 2); _2_combinations = comb2.GetCombinations(); } for (int i = 0; i < CNT; i++) { common.Math.Calculus.MultiFunc f_top_3 = new common.Math.Calculus.MultiFunc(delegate(double x) { double gx = exp(-(x - ee[i]) * (x - ee[i]) / (2 * dd[i] * dd[i])) / (SQRT_2_PI * dd[i]); double[] ret; // 前两个为WIN和PLC的概率 if (PLC_CNT <= 3) { ret = new double[comb_plc.Length + 2]; } else { // 如果PLC_CNT超过3,为了计算前两名的概率,还必须计算我第二名时,其他马第一名的概率 ret = new double[comb_plc.Length + CNT - 1 + 2]; } double[] V, T; calcFx(CNT, PLC_CNT, i, x, ee, dd, out V, out T); ret[0] = T[0]; ret[1] = T.Sum(); // 计算我跑第三(PLC_CNT)时,前两(PLC_CNT-1)名各种组合的概率 double tmp = 1; // 去掉不可能赢之后的概率连乘 int v0count = 0, // 我赢概率为0的数量,即肯定超过我的数量 v1count = 0; // 不可能超过我的数量 for (int j = 0; j < CNT - 1; j++) { if (V[j] == 0) { v0count++; } else if (V[j] == 1) { v1count++; } else { tmp *= V[j]; } } // 肯定超过我的数量v0count大于PLC_CNT-1,我的名次肯定低于PLC_CNT,我跑第PLC_CNT的概率为0 // 不可能超过的数量v1count大于CNT-PLC_CNT,我的名次肯定高于PLC_CNT if (v0count < PLC_CNT && v1count <= CNT - PLC_CNT) { for (int j = 0, j2 = 2; j < comb_plc.Length; j++, j2++) { int[] c = _plc_combinations[j]; int cv0count = 0; ret[j2] = tmp; for (int k = 0; k < PLC_CNT - 1; k++) { if (V[c[k]] == 0) { cv0count++; } else if (V[c[k]] == 1) // 我肯定赢的人在我前面,这个组合不可能存在 { ret[j2] = 0; break; } else { ret[j2] /= V[c[k]]; ret[j2] *= (1 - V[c[k]]); } } if (cv0count < v0count) // 如果组合中没有包含全部肯定赢我的人,这个组合不可能存在 { ret[j2] = 0; } } } // 计算我第二名时各个人第一名的概率 if (PLC_CNT > 3 && v0count < 2 && v1count <= CNT - 2) { for (int j = 0, j2 = 2 + (int)comb_plc.Length; j < CNT - 1; j++, j2++) { if (v0count == 1) { if (V[j] == 0) { ret[j2] = tmp; } else { ret[j2] = 0; } } else { if (V[j] == 1) { ret[j2] = 0; } else { ret[j2] = tmp / V[j] * (1 - V[j]); } } } } return(new common.Math.vector(ret) * gx); }); common.Math.vector pv = common.Math.Calculus.integrate(f_top_3, ee[i] - dd[i] * 7, ee[i] + dd[i] * 7, Math.Pow(10, -PRECISION), 5); p1[i] = pv[0]; p3[i] = pv[1]; if (PLC_CNT > 3) { // PLC_CNT大于3,Q的概率需要通过我第二名时,其他各马第一名的概率计算 int[] c = new int[2]; c[0] = i; // Q的概率 for (int j = 0, j2 = 2 + (int)comb_plc.Length; j < PLC_CNT - 1; j++, j2++) { for (int k = 0; k < PLC_CNT - 1; k++) { if (k < i) { c[1] = k; } else { c[1] = k + 1; } pq_win[combq.Index(c)] += pv[j2]; } } // QP的概率 for (int j = 0, j2 = 2; j < comb_plc.Length; j++, j2++) { // 和我的组合 c[0] = i; for (int k = 0; k < PLC_CNT - 1; k++) { if (_plc_combinations[j][k] < i) { c[1] = _plc_combinations[j][k]; } else { c[1] = _plc_combinations[j][k] + 1; } pq_plc[combq.Index(c)] += pv[j2]; } // 没有我的组合 for (int k = 0; k < _2_combinations.Length; k++) { if (_plc_combinations[j][_2_combinations[k][0]] < i) { c[0] = _plc_combinations[j][_2_combinations[k][0]]; } else { c[0] = _plc_combinations[j][_2_combinations[k][0]] + 1; } if (_plc_combinations[j][_2_combinations[k][1]] < i) { c[1] = _plc_combinations[j][_2_combinations[k][1]]; } else { c[1] = _plc_combinations[j][_2_combinations[k][1]] + 1; } pq_plc[combq.Index(c)] += pv[j2]; } } } else if (PLC_CNT == 3) { // PLC_CNT等于3,Q的概率根据我第三名时,前两名的概率计算 int[] c = new int[2]; for (int j = 0, j2 = 2; j < comb_plc.Length; j++, j2++) { // 和我的组合 c[0] = i; for (int k = 0; k < PLC_CNT - 1; k++) { if (_plc_combinations[j][k] < i) { c[1] = _plc_combinations[j][k]; } else { c[1] = _plc_combinations[j][k] + 1; } pq_plc[combq.Index(c)] += pv[j2]; } // 没有我的组合 if (_plc_combinations[j][0] < i) { c[0] = _plc_combinations[j][0]; } else { c[0] = _plc_combinations[j][0] + 1; } if (_plc_combinations[j][1] < i) { c[1] = _plc_combinations[j][1]; } else { c[1] = _plc_combinations[j][1] + 1; } pq_win[combq.Index(c)] += pv[j2]; pq_plc[combq.Index(c)] += pv[j2]; } } else if (PLC_CNT == 2) { // PLC_CNT等于2,Q/QP是一样的 int[] c = new int[2]; c[0] = i; for (int j = 0, j2 = 2; j < comb_plc.Length; j++, j2++) { // 只有和我的组合 if (_plc_combinations[j][0] < i) { c[1] = _plc_combinations[j][0]; } else { c[1] = _plc_combinations[j][0] + 1; } pq_win[combq.Index(c)] += pv[j2]; } } } }
private static void calcProbilityForFitting(double[] ee, double[] dd, out double[] p1, out double[] pq) { int CNT = ee.Length; p1 = new double[CNT]; common.Math.Combination combq = new common.Math.Combination(CNT, 2); pq = new double[combq.Length]; for (int i = 0; i < CNT; i++) { common.Math.Calculus.MultiFunc f_top_3 = new common.Math.Calculus.MultiFunc(delegate(double x) { double gx = exp(-(x - ee[i]) * (x - ee[i]) / (2 * dd[i] * dd[i])) / (SQRT_2_PI * dd[i]); double[] ret = new double[CNT]; // 第一个为WIN的概率,后面CNT-1个是我第二名时第一名的是各匹马的概率 double[] V, T; calcFx(CNT, 2, i, x, ee, dd, out V, out T); ret[0] = T[0]; // 计算我跑第二时,第一名各马的概率 double tmp = 1; // 去掉不可能赢之后的概率连乘 int v0count = 0, // 我赢概率为0的数量,即肯定超过我的数量 v1count = 0; // 不可能超过我的数量 for (int j = 0; j < CNT - 1; j++) { if (V[j] == 0) { v0count++; } else if (V[j] == 1) { v1count++; } else { tmp *= V[j]; } } // 肯定超过我的数量v0count大于1,我的名次肯定低于2,我跑第2的概率为0 // 不可能超过的数量v1count大于CNT-2,我的名次肯定高于2 if (v0count <= 1 && v1count <= CNT - 2) { for (int j = 0, j2 = 1; j < CNT - 1; j++, j2++) { if (v0count == 1) { if (V[j] == 0) { ret[j2] = tmp; } else { ret[j2] = 0; } } else { if (V[j] == 1) { ret[j2] = 0; } else { ret[j2] = tmp / V[j] * (1 - V[j]); } } } } return(new common.Math.vector(ret) * gx); }); common.Math.vector pv = common.Math.Calculus.integrate(f_top_3, ee[i] - dd[i] * 7, ee[i] + dd[i] * 7, Math.Pow(10, -PRECISION), 5); p1[i] = pv[0]; int[] c = new int[2]; c[0] = i; for (int j = 0, j2 = 1; j < CNT - 1; j++, j2++) { // 只有和我的组合 if (j < i) { c[1] = j; } else { c[1] = j + 1; } pq[combq.Index(c)] += pv[j2]; } } }
public static double[][] calcMinMaxOddsForQp(HrsTable table, double[] betRate, double r) { if (betRate == null) { return(null); } int CNT = table.Count; int PLC_CNT = 3; if (CNT <= table.PLC_SPLIT_POS) { PLC_CNT = 2; } common.Math.Combination comb = new common.Math.Combination(CNT, 2); if (betRate.Length != comb.Length) { return(null); } if (PLC_CNT == 2) { double[] odds = betRate.Select(x => r < x ? 1 : r / x).ToArray(); return(new double[][] { odds, odds }); } else { double[] odds_min = new double[betRate.Length]; double[] odds_max = new double[betRate.Length]; for (int i = 0; i < betRate.Length; i++) { //int[] rel_indices = getQpRelationIndice(comb, i); //double[] rel_rates = new double[rel_indices.Length]; //for (int j = 0; j < rel_indices.Length; j++) rel_rates[j] = betRate[rel_indices[j]]; //IOrderedEnumerable<double> sorted_rate = rel_rates.OrderByDescending(x => x); double br0 = betRate[i]; int[] c = comb.Combine(i); double min = double.MaxValue, max = double.MinValue; for (int j = 0; j < CNT; j++) { if (Array.IndexOf(c, j) == -1) { double br1 = betRate[comb.Index(new int[] { j, c[0] })]; double br2 = betRate[comb.Index(new int[] { j, c[1] })]; double od = 1 + (r - br1 - br2 - br0) / 3 / br0; if (od < min) { min = od; } if (od > max) { max = od; } } } odds_min[i] = min; odds_max[i] = max; } return(new double[][] { odds_min, odds_max }); } }
private void calc(double[] ee, double[] dd, out double[] p1, out double[] p3, out double[] p3detail) { p1 = new double[CNT]; p3 = new double[CNT]; common.Math.Combination comb3 = new common.Math.Combination(CNT, PLC_CNT); p3detail = new double[comb3.Length]; common.Math.Combination comb2 = new common.Math.Combination(CNT - 1, PLC_CNT - 1); int[][] _2_combinations = comb2.GetCombinations(); for (int i = 0; i < CNT; i++) { common.Math.Calculus.Func r = new common.Math.Calculus.Func(delegate(double x) { double ret = 1; for (int j = 0; j < CNT; j++) { if (j == i) { continue; } ret += this.gauss(ee[j], dd[j], x); } return(ret); }); // @deprecated f_top1没用了,在f_top3中计算了 common.Math.Calculus.Func f_top1 = new common.Math.Calculus.Func(delegate(double x) { double gx = this.exp(-(x - ee[i]) * (x - ee[i]) / (2 * dd[i] * dd[i])) / (SQRT_2_PI * dd[i]); double rx = 1; for (int j = 0; j < CNT; j++) { if (j == i) { continue; } rx *= 1 - this.gauss(ee[j], dd[j], x); } return(gx * rx); // 这里应该是将我跑x的成绩时,赢每个人的概率连乘,转换为其中0个人赢我的泊松分布概率 2017-3-7 // 这样子不行的,比如假设A赢我概率0.5,B赢我概率0.5,没有人能赢我的概率是0.5*0.5 = 0.25 // 转换后,A赢我的期望0.5+B赢我的期望0.5=1,泊松分布概率P(0)=0.368,差蛮远 //double rv = Math.Exp(-r(x)); //return gx * rv; }); common.Math.Calculus.MultiFunc f_top_3 = new common.Math.Calculus.MultiFunc(delegate(double x) { double gx = this.exp(-(x - ee[i]) * (x - ee[i]) / (2 * dd[i] * dd[i])) / (SQRT_2_PI * dd[i]); double[] ret = new double[comb2.Length + 2]; // 前两个为WIN和PLC的概率 // 选2 Tree最后的结果就是有两个人赢我的概率 // 选1 Tree最后的结果是有一个人赢我的概率 // LS最后结果是没人赢我的概率 // // 不选A - “选2 Tree” V(A)*2T // / // root + 不选B - “选1 Tree” // \ / // 选A - “选1 Tree” (1-V(A))*1T --- // \ // 选B - 连乘 //2T(n-2) = (1-V(n-1)) * (1-V(n-2)) //2T(d) = V(d)*2T(d+1)+(1-V(d))*1T(d+1) //1T(n-1) = (1-V(n-1)) //1T(d) = V(d)*1T(d+1)+(1-V(d))*LS(d+1) //LS(n-1) = V(n-1) //LS(d) = V(d)*LS(d+1) // 目标计算2T(0) // // 扩展3T、4T、jT // jT(n-j) = (1-V(n-1))*...*(1-V(n-j)) // jT(d) = V(d)*jT(d+1)+(1-V(d))*(j-1)T(d+1) double[] V = new double[CNT - 1]; // 我赢i的概率 for (int j = 0; j < CNT; j++) { if (j < i) { V[j] = 1 - this.gauss(ee[j], dd[j], x); } else if (j > i) { V[j - 1] = 1 - this.gauss(ee[j], dd[j], x); } else // if (j == i) { continue; } } int n = CNT - 1; double[] T = new double[PLC_CNT]; for (int j = 0; j < PLC_CNT; j++) { T[j] = 1; for (int k = 1; k <= j; k++) { T[j] *= 1 - V[n - k]; } } for (int j = n - 1; j >= 0; j--) { for (int k = 0; k < PLC_CNT; k++) { if (k == 0) { T[k] *= V[j]; } else if (j - k >= 0) { T[k] = V[j - k] * T[k] + (1 - V[j - k]) * T[k - 1]; } } } ret[0] = T[0]; ret[1] = T.Sum(); // 计算我跑第三(PLC_CNT)时,前两(PLC_CNT-1)名各种组合的概率 double tmp = 1; int[] v0indices = new int[CNT - 1]; int v0count = 0, // 我赢概率为0的数量,即肯定超过我的数量 v1count = 0; // 不可能超过我的数量 for (int j = 0; j < CNT - 1; j++) { if (V[j] == 0) { v0indices[v0count++] = j; } else if (V[j] == 1) { v1count++; } else { tmp *= V[j]; } } // 肯定超过我的数量v0count大于PLC_CNT-1,我的名次肯定低于PLC_CNT,我跑第PLC_CNT的概率为0 // 不可能超过的数量v1count大于CNT-PLC_CNT,我的名次肯定高于PLC_CNT if (v0count < PLC_CNT && v1count <= CNT - PLC_CNT) { for (int j = 0; j < comb2.Length; j++) { int[] c = _2_combinations[j]; int cv0count = 0; ret[j + 2] = tmp; for (int k = 0; k < PLC_CNT - 1; k++) { if (V[c[k]] == 0) { cv0count++; } else if (V[c[k]] == 1) { ret[j + 2] = 0; break; } else { ret[j + 2] /= V[c[k]]; ret[j + 2] *= (1 - V[c[k]]); } } if (cv0count < v0count) { ret[j + 2] = 0; } } } return(new common.Math.vector(ret) * gx); }); //p1[i] = common.Math.Calculus.integrate(f_top1, ee[i] - dd[i] * 8, ee[i] + dd[i] * 8, Math.Pow(10, -PRECISION), 5); //p3[i] = common.Math.Calculus.integrate(f_top3, ee[i] - dd[i] * 8, ee[i] + dd[i] * 8, Math.Pow(10, -PRECISION), 5); common.Math.vector pv = common.Math.Calculus.integrate(f_top_3, ee[i] - dd[i] * 7, ee[i] + dd[i] * 7, Math.Pow(10, -PRECISION), 5); p1[i] = pv[0]; p3[i] = pv[1]; for (int j = 0; j < comb2.Length; j++) { int[] c = new int[PLC_CNT]; c[0] = i; for (int k = 0; k < PLC_CNT - 1; k++) { if (_2_combinations[j][k] < i) { c[k + 1] = _2_combinations[j][k]; } else { c[k + 1] = _2_combinations[j][k] + 1; } } p3detail[comb3.Index(c)] += pv[j + 2]; } } }
private void btn逆向过程_Click(object sender, EventArgs e) { this.btn逆向过程.Enabled = false; if (_t_o == null) { _t_o = new Thread(new ThreadStart(delegate { try { this.Invoke(new MethodInvoker(delegate { this.btn逆向过程.Enabled = true; this.btn逆向过程.Text = "停止"; })); double[] fp1 = rows["TOP1概率"]; double[] fp3 = rows["TOP3概率"]; double[] s1 = rows["TOP1 SP"]; double[] s3 = rows["TOP3 SP"]; double[] ee = new double[CNT]; double[] dd = new double[CNT]; double rr1 = 1 / s1.Sum(x => 1 / x); // 计算WIN投注比率 double[] ph1 = new double[CNT]; for (int i = 0; i < CNT; i++) { ph1[i] = rr1 / s1[i]; } // 计算PLC赔付率 IOrderedEnumerable <double> sorted_s3 = s3.OrderBy(x => x); double o3 = sorted_s3.Skip(2).First(); double a = 3 * (o3 - 1) / (3 * (o3 - 1) + 1) * sorted_s3.Take(2).Sum(x => 1 / (3 * (x - 1))); double b = sorted_s3.Skip(2).Sum(x => 1 / (3 * (x - 1) + 1)); double rr3 = (a + 1) / (a + b); // 计算投注比例 double po3 = (1 - rr3) / ((sorted_s3.Skip(2).Sum(x => 1 / (3 * x - 2)) - 1) * (3 * o3 - 2)); double[] ph3 = new double[CNT]; for (int i = 0; i < CNT; i++) { if (s3[i] <= o3) { ph3[i] = po3 * (o3 - 1) / (s3[i] - 1); } else { ph3[i] = po3 * (3 * o3 - 2) / (3 * s3[i] - 2); } } // 设定top1第3的项期望=0,方差=1 double trd_s1 = s1.OrderBy(x => x).Skip(2).First(); int trd_inx = -1; for (int i = 0; i < CNT; i++) { if (s1[i] == trd_s1) { trd_inx = i; break; } } if (trd_inx == -1) { MessageBox.Show("没想到找不到排行第3的项"); return; } ee[trd_inx] = 0; dd[trd_inx] = 1; // 初始化其他项 // 目前全部设为期望=0,方差=1 // 后面考虑根据s1设置 for (int i = 0; i < CNT; i++) { if (i == trd_inx) { continue; } ee[i] = 0; dd[i] = 1; } double lastE = double.MaxValue; int[] dir_d_rr_ee = new int[CNT], dir_d_rr_dd = new int[CNT]; for (int t = 0; ; t++) { double[] p1, p3, p3detail; this.calc(ee, dd, out p1, out p3, out p3detail); double E = 0; // 交叉熵损失以及交叉熵损失对与各个概率的梯度 double[] grad_p1 = new double[CNT], grad_p3 = new double[CNT]; for (int i = 0; i < CNT; i++) { E += -(ph1[i] * Math.Log(p1[i]) + (1 - ph1[i]) * Math.Log(1 - p1[i])); E += -(ph3[i] * Math.Log(p3[i]) + (1 - ph3[i]) * Math.Log(1 - p3[i])); grad_p1[i] = -(ph1[i] / p1[i] - (1 - ph1[i]) / (1 - p1[i])); grad_p3[i] = -(ph3[i] / p3[i] - (1 - ph3[i]) / (1 - p3[i])); } //double rr = this.calc_rr(s1, p1, s3, p3); double maxr1 = double.MinValue, minr1 = double.MaxValue, maxr3 = double.MinValue, minr3 = double.MaxValue; int maxr1_i = -1, minr1_i = -1, maxr3_i = -1, minr3_i = -1; double[] r1 = new double[CNT], r3 = new double[CNT]; // 这个是每个马的回报率,非赔付率 common.Math.Combination comb = new common.Math.Combination(CNT, PLC_CNT); int[][] combs = comb.GetCombinations(); for (int i = 0; i < CNT; i++) { r1[i] = s1[i] * p1[i]; r3[i] = this.calc_plc_r(rr3, i, ph3, p3detail, combs); if (r1[i] > maxr1) { maxr1 = r1[i]; maxr1_i = i; } if (r1[i] < minr1) { minr1 = r1[i]; minr1_i = i; } if (r3[i] > maxr3) { maxr3 = r3[i]; maxr3_i = i; } if (r3[i] < minr3) { minr3 = r3[i]; minr3_i = i; } } // 求对各个参数的梯度 double[] d_rr_ee = new double[CNT]; double[] d_rr_dd = new double[CNT]; for (int i = 0; i < CNT; i++) { // if (i == trd_inx) continue; double[] tp1, tp3, tp3detail; ee[i] += EE_D_INC; this.calc(ee, dd, out tp1, out tp3, out tp3detail); for (int j = 0; j < CNT; j++) { // 第j匹马的WIN概率对第i匹马的均值的梯度 = (tp1[j] - p1[j]) / EE_D_INC d_rr_ee[i] += (tp1[j] - p1[j]) / EE_D_INC * grad_p1[j]; // 第j匹马的PLC概率对第i匹马的均值的梯度 = (tp3[j] - p3[j]) / EE_D_INC d_rr_ee[i] += (tp3[j] - p3[j]) / EE_D_INC * grad_p3[j]; } ee[i] -= EE_D_INC; dd[i] += DD_D_INC; this.calc(ee, dd, out tp1, out tp3, out tp3detail); for (int j = 0; j < CNT; j++) { // 第j匹马的WIN概率对第i匹马的方差的梯度 = (tp1[j] - p1[j]) / DD_D_INC d_rr_dd[i] += (tp1[j] - p1[j]) / DD_D_INC * grad_p1[j]; // 第j匹马的PLC概率对第i匹马的方差的梯度 = (tp3[j] - p3[j]) / DD_D_INC d_rr_dd[i] += (tp3[j] - p3[j]) / DD_D_INC * grad_p3[j]; } dd[i] -= DD_D_INC; } // 调整各参数 for (int i = 0; i < CNT; i++) { // if (i == trd_inx) continue; if (d_rr_ee[i] > 0 && dir_d_rr_ee[i] >= 0) { dir_d_rr_ee[i]++; } else if (d_rr_ee[i] < 0 && dir_d_rr_ee[i] <= 0) { dir_d_rr_ee[i]--; } else { dir_d_rr_ee[i] = 0; } if (d_rr_dd[i] > 0 && dir_d_rr_dd[i] >= 0) { dir_d_rr_dd[i]++; } else if (d_rr_dd[i] < 0 && dir_d_rr_dd[i] <= 0) { dir_d_rr_dd[i]--; } else { dir_d_rr_dd[i] = 0; } // 向负梯度方向调整 ee[i] += -d_rr_ee[i] * EE_STEP / (1 + t * STEP_DECAY) * (1 + Math.Abs(dir_d_rr_ee[i]) * STEP_DECAY); dd[i] += -d_rr_dd[i] * DD_STEP / (1 + t * STEP_DECAY) * (1 + Math.Abs(dir_d_rr_dd[i]) * STEP_DECAY); if (dd[i] < 0.0001) { dd[i] = 0.0001; } } // 调整之后再进行归一化 for (int i = 0; i < CNT; i++) { if (i == trd_inx) { continue; } ee[i] = (ee[i] - ee[trd_inx]) / dd[trd_inx]; dd[i] = dd[i] / dd[trd_inx]; } ee[trd_inx] = 0; dd[trd_inx] = 1; //E = r1.Sum(x => (x - rr1) * (x - rr1)) + r3.Sum(x => (x - rr3) * (x - rr3)); this.Invoke(new MethodInvoker(delegate { for (int i = 0; i < CNT; i++) { lves[i].Text = string.Format("{0:0.0000}", ee[i]); lvds[i].Text = string.Format("{0:0.0000}", dd[i]); lres[i].Text = string.Format("{0:0.0000}", d_rr_ee[i]); lrds[i].Text = string.Format("{0:0.0000}", d_rr_dd[i]); lpws[i].Text = string.Format("{0:0.0000}", p1[i] * 100); lpps[i].Text = string.Format("{0:0.0000}", p3[i] * 100); lrcws[i].Text = string.Format("{0:0.0000}", p1[i] * s1[i]); lrcps[i].Text = string.Format("{0:0.0000}", p3[i] * s3[i]); lrfws[i].Text = string.Format("{0:0.0000}", fp1[i] * s1[i]); lrfps[i].Text = string.Format("{0:0.0000}", fp3[i] * s3[i]); } for (int i = 0; i < CNT; i++) { if (i != maxr1_i && i != minr1_i) { lpws[i].BackColor = Color.White; } if (i != maxr3_i && i != minr3_i) { lpps[i].BackColor = Color.White; } } lpws[maxr1_i].BackColor = Color.Yellow; lpws[minr1_i].BackColor = Color.Red; lpps[maxr3_i].BackColor = Color.Yellow; lpps[minr3_i].BackColor = Color.Red; for (int i = lEs.Length - 1; i > 0; i--) { lEs[i].Text = lEs[i - 1].Text; } lEs[0].Text = string.Format("{2}: {0:0.0000} | {1:0.0000000}", E, 1 / (1 + t * STEP_DECAY), t); lpwSum.Text = string.Format("{0:0.0000}", p1.Sum() * 100); lppSum.Text = string.Format("{0:0.0000}", p3.Sum() * 100); })); if (E > lastE) { break; } } } finally { _t_o = null; try { this.Invoke(new MethodInvoker(delegate { this.btn逆向过程.Enabled = true; this.btn逆向过程.Text = "逆向过程"; })); } catch { } } })); _t_o.IsBackground = true; _t_o.Start(); } else { _t_o.Abort(); } }