Ejemplo n.º 1
0
        private void button1_Click(object sender, EventArgs e)
        {
            HrsTable table = new HrsTable();

            table.Add(new Hrs("1", 5.5, 2.3));
            table.Add(new Hrs("2", 9.1, 1.6));
            table.Add(new Hrs("3", 44.9, 8.2));
            table.Add(new Hrs("4", 4.9, 2.7));
            table.Add(new Hrs("5", 16.3, 2.4));
            table.Add(new Hrs("6", 3.4, 1.5));
            table.Add(new Hrs("7", 15.6, 2.3));
            table.Add(new Hrs("8", 33.3, 4.4));
            table.Add(new Hrs("9", 17.3, 2.7));
            table.Add(new Hrs("10", 16.1, 3.4));
            table.Add(new Hrs("11", 40.1, 6.4));
            table.Add(new Hrs("12", 36, 5.7));
            table.Add(new Hrs("13", 42.7, 6.7));

            double E = Fitting.fit(table, 0.00001);

            MessageBox.Show(E.ToString());
        }
Ejemplo n.º 2
0
        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();
                    }
                }
            }
        }
Ejemplo n.º 3
0
        private void btnFit_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.InitialDirectory = Application.StartupPath;
                dlg.Multiselect      = true;

                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.btnFit.Enabled = false;

                    Thread t = new Thread(delegate(object args)
                    {
                        string[] filenames = (string[])args;
                        foreach (string filename in dlg.FileNames)
                        {
                            RaceData race = RaceData.Load(filename);

                            int i = 0;
                            foreach (KeyValuePair <long, RaceDataItem> item in race)
                            {
                                if (i++ == -1)
                                {
                                    continue;
                                }
                                this.Invoke(new MethodInvoker(delegate
                                {
                                    this.txtFitLog.AppendText(string.Format("{0:HH:mm:ss} > {1} of {2} fitting...\r\n", DateTime.Now, item.Key, filename));
                                }));

                                item.Value.Odds.ClearSCR();
                                double E          = Fitting.fit(item.Value.Odds, 0.0001);
                                item.Value.Odds.E = E;

                                this.Invoke(new MethodInvoker(delegate
                                {
                                    this.txtFitLog.AppendText(string.Format("{0:HH:mm:ss} > {1} of {2} E = {3}\r\n", DateTime.Now, item.Key, filename, E));
                                }));

                                if (i >= 2)
                                {
                                    break;
                                }
                            }

                            Match m = Regex.Match(filename, @"^(.+?)\.fit(\d*)$");
                            if (m.Success)
                            {
                                if (m.Groups[2].Value == "")
                                {
                                    race.Save(m.Groups[1].Value + ".fit2");
                                }
                                else
                                {
                                    race.Save(m.Groups[1].Value + ".fit" + (int.Parse(m.Groups[2].Value) + 1).ToString());
                                }
                            }
                            else
                            {
                                race.Save(filename + ".fit");
                            }


                            this.Invoke(new MethodInvoker(delegate
                            {
                                this.txtFitLog.AppendText(string.Format("{0:HH:mm:ss} > file {1} finished\r\n", DateTime.Now, filename));
                            }));
                        }

                        this.Invoke(new MethodInvoker(delegate
                        {
                            this.txtFitLog.AppendText(string.Format("{0:HH:mm:ss} > all finished\r\n", DateTime.Now));
                            this.btnFit.Enabled = true;
                        }));
                    });
                    t.Start(dlg.FileNames);
                }
            }
        }