package daemon import ( "fmt" "sort" "strconv" "strings" "time" "gordenko.dev/dima/flashscore" "gordenko.dev/dima/onexbet" "gordenko.dev/dima/tipper/model" "gordenko.dev/dima/web/api" "gordenko.dev/dima/ws" ) func (s *Daemon) tryLinkToLiveMatch(sportID int, liveMatch onexbet.LiveMatch) { matchName := fmt.Sprintf("%s - %s", liveMatch.Home, liveMatch.Away) s.logger.Printf("try link: %s\n", matchName) // Если уже распознан - пропускаем // На всякий пожарный проверка //_, ok := s.onexbetMatchToTeamMatch[liveMatch.MatchID] //if ok { // s.logger.Printf("try link: %s\n", matchName) // return //} // Если этот матч уже проверяли - игнорируем s.mutex.Lock() unrecognizedMatches, ok := s.unrecognizedOnexbetMatches[sportID] if !ok { s.logger.Printf("unrecognized matches for the sport %d not found\n", sportID) return } if unrecognizedMatches[liveMatch.MatchID] { //s.logger.Printf("Match (%s) is unrecognized. Don't repeat identification\n", matchName) s.mutex.Unlock() return } s.mutex.Unlock() homeTeamCandidates, err := s.fsmodel.ListTeamCandidates(sportID, liveMatch.Home) if err != nil { s.logger.Printf("fsmodel.ListFootballTeamCandidates: %s\n", err) return } //s.logger.Printf("homeTeamCandidates (for %s): %q", liveMatch.Home, homeTeamCandidates) awayTeamCandidates, err := s.fsmodel.ListTeamCandidates(sportID, liveMatch.Away) if err != nil { s.logger.Printf("fsmodel.ListFootballTeamCandidates: %s\n", err) return } //s.logger.Printf("awayTeamCandidates (for %s): %q", liveMatch.Away, awayTeamCandidates) // teamMatches, ok := s.teamMatches[sportID] if !ok { err = fmt.Errorf("Not found matches for the sportID %d", sportID) return } for _, match := range teamMatches { var isTeamsSwapped bool isIdentified := s.tryIdentifyMatch(match.Home.TeamID, match.Away.TeamID, homeTeamCandidates, awayTeamCandidates) if !isIdentified { // Пробуем опознать если home и away поменять местами isIdentified = s.tryIdentifyMatch(match.Home.TeamID, match.Away.TeamID, awayTeamCandidates, homeTeamCandidates) isTeamsSwapped = true } if isIdentified { if !match.Home.WasLinked { err = s.fsmodel.SetTeamWasLinked(match.Home.TeamID) if err != nil { s.logger.Printf("fsmodel.SetTeamWasLinked: %s; teamID=%s\n", err, match.Home.TeamID) } s.mutex.Lock() match.Home.WasLinked = true s.mutex.Unlock() } if !match.Away.WasLinked { err = s.fsmodel.SetTeamWasLinked(match.Away.TeamID) if err != nil { s.logger.Printf("fsmodel.SetTeamWasLinked: %s; teamID=%s\n", err, match.Away.TeamID) } s.mutex.Lock() match.Away.WasLinked = true s.mutex.Unlock() } s.mutex.Lock() match.IsLinkedToOnexbet = true match.OnexbetMatchID = liveMatch.MatchID match.OnexbetStatsMatchID = liveMatch.StatsMatchID match.Score = liveMatch.Score match.ScoreByPeriods = liveMatch.ScoreByPeriods match.CurrentPeriod = liveMatch.CurrentPeriod match.IsTeamsSwapped = isTeamsSwapped s.onexbetMatchToTeamMatch[liveMatch.MatchID] = match s.identifiedMatches[liveMatch.MatchID] = true s.logger.Printf("Identified: %s; %s; %s\n", matchName, liveMatch.MatchID, match.MatchID) // Матч опознан и перешел в inplay s.publisher.Publish( getChannel(match.SportID), WSMessageInplayStatusChanged, InplayStatusMessage{ MatchID: match.MatchID, IsInplay: match.IsInplay, IsLinkedToOnexbet: match.IsLinkedToOnexbet, }, ) s.mutex.Unlock() return } } s.mutex.Lock() // Кешируем негативный результат, чтобы не искать в базе ежеминутно // Если пользователь распознает новые матчи, - кэш будет очищен unrecognizedMatches, ok = s.unrecognizedOnexbetMatches[sportID] if !ok { return } unrecognizedMatches[liveMatch.MatchID] = true s.mutex.Unlock() s.logger.Printf("Match (%s; %s) is not identified. Added to unrecognized\n", matchName, liveMatch.MatchID) } func (s *Daemon) tryIdentifyMatch(homeTeamID, awayTeamID string, homeTeamCandidates, awayTeamCandidates []string) (_ bool) { for _, candidateHomeTeamID := range homeTeamCandidates { if homeTeamID == candidateHomeTeamID { // Если нашли совпадение для home - ищем совпадение для away for _, candidateAwayTeamID := range awayTeamCandidates { if awayTeamID == candidateAwayTeamID { // Mатч идентифицирован return true } } } } return } func (s *Daemon) onOnexbetWsClientConnected(conn *ws.Conn) { s.logger.Printf("Onexbet Ws Client Connected\n") } /* func (s *Daemon) onOnexbetMatchFinished(conn *ws.Conn, in onexbet.WatchReq) { s.mutex.Lock() defer s.mutex.Unlock() match, ok := s.onexbetMatchToTeamMatch[in.MatchID] if !ok { return } match.IsInplay = false } */ func (s *Daemon) onOnexbetTeamLiveMatches(conn *ws.Conn, in onexbet.LiveMatchesMessage) { //s.logger.Println("onOnexbetTeamLiveMatches") //s.logger.Printf("onexbetMatchToTeamMatch size: %d\n", len(s.onexbetMatchToTeamMatch)) sportID, ok := onexbetSportToFlashscoreSport[in.SportID] if !ok { s.logger.Printf("Bug: unknown OnexbetSport %d\n", in.SportID) return } s.logger.Printf("Onexbet live matches: %d, watching: %d; Inplay: %d\n", len(in.Matches), len(in.Watching), len(s.onexbetMatchToTeamMatch)) liveMap := make(map[string]onexbet.LiveMatch) // В цикле рашем 3 задачи: // - формируем словарь из live матчей на сайте 1xBet, для удобства дальнейшей обработки // - для матчей в inplay проверяем не появился ли liveMatch.StatsMatchID, по которому // можно будет узнать результат матча на сайте 1xBet // - пытаемся распознать новые матчи for _, liveMatch := range in.Matches { liveMap[liveMatch.MatchID] = liveMatch match, ok := s.onexbetMatchToTeamMatch[liveMatch.MatchID] if ok { s.logger.Printf("Match (%s - %s) already identified\n", match.Home.CanonicalName, match.Away.CanonicalName) // ВАЖНО! // liveMatch.StatsMatchID появится когда матч перейдет в лайв. if match.OnexbetStatsMatchID == "" && liveMatch.StatsMatchID != "" { match.OnexbetStatsMatchID = liveMatch.StatsMatchID match.Score = liveMatch.Score match.ScoreByPeriods = liveMatch.ScoreByPeriods match.CurrentPeriod = liveMatch.CurrentPeriod } } else { if !s.identifiedMatches[liveMatch.MatchID] { // Матча нет среди распознанных - пытаемся опознать s.tryLinkToLiveMatch(sportID, liveMatch) } } } var watchingMap = make(map[string]bool) for _, onexbetMatchID := range in.Watching { watchingMap[onexbetMatchID] = true _, isMatchInInplay := s.onexbetMatchToTeamMatch[onexbetMatchID] if !isMatchInInplay { // Матча больше нет в inplay. Если 1xbet присылает его в Watching - // значит API-запрос Unwatch где-то потерялся. Поэтому отправляем снова. s.onexbetAPIClient.Call(api.CallReq{ FuncName: "unwatch", In: onexbet.WatchReq{ SportID: in.SportID, MatchID: onexbetMatchID, }, }) } } // Цикл по inplay матчам //if sportID == flashscore.Tennis { // //s.checkInplayTennisMatches(liveMap, watchingMap) //} else { s.checkInplayTeamMatches(sportID, in.SportID, liveMap, watchingMap) //} } //func (s *Daemon) checkInplayTennisMatches(liveMap map[string]bool, watchingMap map[string]bool) { //for onexbetMatchID, match := range s.onexbetMatchToTeamMatch { //if match. //} //} func (s *Daemon) checkInplayTeamMatches(sportID int, onexbetSportID onexbet.OnexbetSport, liveMap map[string]onexbet.LiveMatch, watchingMap map[string]bool) { for onexbetMatchID, match := range s.onexbetMatchToTeamMatch { if match.SportID != sportID { // Если другой спорт - пропускаем матч continue } liveMatch, isIn1xbetLive := liveMap[onexbetMatchID] if !isIn1xbetLive { // МАТЧИ могут просто исчезать из ЛАЙВ списка, поэтому просто удалять // нельзя! Сперва запросим результат матча у 1xbet и решим что делать. //err := s.processMatchDisappearedFromLive(match, onexbetMatchID) //if err != nil { // s.logger.Printf("processMatchDisappearedFromLive: %s\n", err) //} s.logger.Printf("Inplay match (%s - %s) not found in 1xbet live matches. Remove from inplay\n", match.Home.CanonicalName, match.Away.CanonicalName) s.removeMatchFromInplay(match, onexbetMatchID) } else { if !watchingMap[onexbetMatchID] { // Матч есть в лайве 1xbet (liveMap) - но нет в наблюдаемых. Например, // перезагрузился 1xbet демон, или отписались. if len(match.Strategies) > 0 { // Если еще есть не сработавшие стратегии - начинаем наблюдать. //s.logger.Printf("Watch: %d, %s\n", in.SportID, onexbetMatchID) // Подписываемся на матчи, которые только что идентифицировали + на те, которые // пропали из watch списка (например из-за перезагрузки 1xBET демона) for _, strategy := range match.Strategies { if strategy.IsNeedToWatch(liveMatch) { // Если хотя бы одной стратегии нужно наблюдать за матчем // - подписываемся и прерываем цикл match.IsInplay = true s.onexbetAPIClient.Call(api.CallReq{ FuncName: "watch", In: onexbet.WatchReq{ SportID: onexbetSportID, MatchID: onexbetMatchID, }, }) s.mutex.Lock() // Матч дабавили в inplay s.publisher.Publish( getChannel(match.SportID), WSMessageInplayStatusChanged, InplayStatusMessage{ MatchID: match.MatchID, IsInplay: match.IsInplay, IsLinkedToOnexbet: match.IsLinkedToOnexbet, }, ) s.mutex.Unlock() // ВАЖНО! break } } } else { s.mutex.Lock() //s.logger.Printf("Unwatch: %d, %s\n", in.SportID, onexbetMatchID) // Матч больше не интересен // Все стратегии сработали - отписываемся от матча delete(s.onexbetMatchToTeamMatch, onexbetMatchID) match.IsInplay = false s.onexbetAPIClient.Call(api.CallReq{ FuncName: "unwatch", In: onexbet.WatchReq{ SportID: onexbetSportID, MatchID: onexbetMatchID, }, }) // Матч убрали из inplay s.publisher.Publish( getChannel(match.SportID), WSMessageInplayStatusChanged, InplayStatusMessage{ MatchID: match.MatchID, IsInplay: match.IsInplay, IsLinkedToOnexbet: match.IsLinkedToOnexbet, }, ) s.mutex.Unlock() } } else { // Матч есть в лайве 1xbet (liveMap) и в наблюдаемых - все OK. // Ничего не делаем. } } } } /* func (s *Daemon) processMatchDisappearedFromLive(match *TeamMatch, onexbetMatchID string) (err error) { if match.OnexbetStatsMatchID == "" { // Ситуация возвожна, когда матч появился на короткий срок, OnexbetStatsMatchID еще // не получил и затем исчез. err = fmt.Errorf("1xBet match %s has empty OnexbetStatsMatchID", onexbetMatchID) return } matchResult, err := onexbet.GetTeamMatchResult(match.OnexbetStatsMatchID) if err != nil { err = fmt.Errorf("onexbet.GetTeamMatchResult: %s", err) return } if matchResult.Status != onexbet.StatusMatchCompleted { // Если матч не завершен - пропускаем. Предполагаем что матч просто // временно исчез из лайва return } // Матч завершен - загружаем прогнозы, чтобы выставить результаты tips, err := s.model.ListMatchTips(match.MatchID) if err != nil { err = fmt.Errorf("model.ListMatchTips: %s; matchID=%s", err, match.MatchID) return } if len(tips) > 0 { // На один матч может быть несколько прогнозов, поэтому важно знать что результаты // всех прогнозов удалось записать в БД. Пока все результаты записать не удастся - // это метод будет вызыватся снова и снова. for _, tip := range tips { err = s.trySetTipResult(tip, matchResult) if err != nil { err = fmt.Errorf("trySetTipResult: %s; tipID=%d", err, tip.TipID) return } } } // Результат всех прогнозов по матчу успешно записан либо прогнозов не было. // В любом случае - удаляем матч из лайва. s.removeMatchFromInplay(match, onexbetMatchID) return } */ func (s *Daemon) removeMatchFromInplay(match *TeamMatch, onexbetMatchID string) { s.mutex.Lock() defer s.mutex.Unlock() delete(s.onexbetMatchToTeamMatch, onexbetMatchID) match.IsInplay = false // Матч убрали из inplay s.publisher.Publish( getChannel(match.SportID), WSMessageInplayStatusChanged, InplayStatusMessage{ MatchID: match.MatchID, IsInplay: match.IsInplay, IsLinkedToOnexbet: match.IsLinkedToOnexbet, }, ) } type WhyNot struct { MatchID string `json:"matchID"` Comment string `json:"comment"` Time string `json:"time"` HomeGoals int `json:"homeGoals"` AwayGoals int `json:"awayGoals"` GamePace float64 `json:"gamePace"` GamePaceFrame int `json:"gamePaceFrame"` // count from Zero } //func (s *Daemon) onOnexbetTennisLiveMatchData(conn *ws.Conn, upd onexbet.TeamLiveMatchData) { // s.mutex.Lock() // defer s.mutex.Unlock() // s.logger.Printf("tennis MatchData: %s\n", upd.MatchID) //} /* type TeamLiveMatchData struct { MatchID string `json:"matchID"` HomeAttacks int `json:"homeAttacks"` HomeDangerousAttacks int `json:"homeDangerousAttacks"` HomeShotsOnTarget int `json:"homeShotsOnTarget"` HomeShotsOffTarget int `json:"homeShotsOffTarget"` AwayAttacks int `json:"awayAttacks"` AwayDangerousAttacks int `json:"awayDangerousAttacks"` AwayShotsOnTarget int `json:"awayShotsOnTarget"` AwayShotsOffTarget int `json:"awayShotsOffTarget"` CurrentTime int `json:"currentTime"` HomeGoals int `json:"homeGoals"` AwayGoals int `json:"awayGoals"` Winner *Winner3Way `json:"winner"` Total Total `json:"total"` Handicap Handicap `json:"handicap"` IndividualTotalHome Total `json:"individualTotalHome"` IndividualTotalAway Total `json:"individualTotalAway"` H1 Half `json:"h1"` // 1st half // tennis Winner2Way *Winner2Way `json:"winner2way"` // score Score Score `json:"score"` ScoreByPeriods map[int]Score `json:"scoreByPeriods"` CurrentPeriod int `json:"currentPeriod"` Periods map[int]Period `json:"periods"` } */ func swapTeamLiveMatchData(d onexbet.TeamLiveMatchData) onexbet.TeamLiveMatchData { d.AwayAttacks, d.HomeAttacks = d.HomeAttacks, d.AwayAttacks d.AwayDangerousAttacks, d.HomeDangerousAttacks = d.HomeDangerousAttacks, d.AwayDangerousAttacks d.AwayShotsOnTarget, d.HomeShotsOnTarget = d.HomeShotsOnTarget, d.AwayShotsOnTarget d.AwayShotsOffTarget, d.HomeShotsOffTarget = d.HomeShotsOffTarget, d.AwayShotsOffTarget d.AwayGoals, d.HomeGoals = d.HomeGoals, d.AwayGoals if d.Winner != nil { d.Winner.Away, d.Winner.Home = d.Winner.Home, d.Winner.Away } if d.Winner2Way != nil { d.Winner2Way.Away, d.Winner2Way.Home = d.Winner2Way.Home, d.Winner2Way.Away } d.Handicap.Away, d.Handicap.Home = d.Handicap.Home, d.Handicap.Away d.IndividualTotalAway, d.IndividualTotalHome = d.IndividualTotalHome, d.IndividualTotalAway d.H1.IndividualTotalAway, d.H1.IndividualTotalHome = d.H1.IndividualTotalHome, d.H1.IndividualTotalAway d.Score.Away, d.Score.Home = d.Score.Home, d.Score.Away for periodNumber, score := range d.ScoreByPeriods { score.Away, score.Home = score.Home, score.Away d.ScoreByPeriods[periodNumber] = score } for periodNumber, period := range d.Periods { period.Handicap.Away, period.Handicap.Home = period.Handicap.Home, period.Handicap.Away d.Periods[periodNumber] = period } return d } func (s *Daemon) onOnexbetTeamLiveMatchData(conn *ws.Conn, upd onexbet.TeamLiveMatchData) { s.mutex.Lock() defer s.mutex.Unlock() s.logger.Printf("MatchData: %s\n", upd.MatchID) // маппинг - match, ok := s.onexbetMatchToTeamMatch[upd.MatchID] if !ok { return } if match.IsTeamsSwapped { upd = swapTeamLiveMatchData(upd) } //if match.SportID == flashscore.Handball { //x, _ := json.MarshalIndent(upd, "", " ") //fmt.Printf("MatchID: %s (1xbet MatchID: %s), Time: %d, HomeGoals: %d, AwayGoals: %d\n", // match.MatchID, upd.MatchID, upd.CurrentTime, upd.HomeGoals, upd.AwayGoals) //} channel := getChannel(match.SportID) //s.logger.Printf("Onexbet TeamLiveMatchData: sportID %d, channel %s\n", match.SportID, channel) var ( triggeredStrategyIDs []int64 comments []string strategyIDs []int ) for strategyID := range match.Strategies { strategyIDs = append(strategyIDs, int(strategyID)) } sort.Ints(strategyIDs) for _, strategyID := range strategyIDs { strategy := match.Strategies[int64(strategyID)] // Если по стратегии уже дали прогноз //if match.EndedStrategies[strategy.ID()] { // continue //} whyNot, bet, code := strategy.GetTip(match, upd) switch code { case Waiting: // pass //s.logger.Printf("Waiting: %s\n", whyNot) // Отправить в websocket comments = append(comments, fmt.Sprintf("%s:
%s", strategy.ShortName(), whyNot)) case Unwatch: s.logger.Printf("Unwatch: %s\n", whyNot) triggeredStrategyIDs = append(triggeredStrategyIDs, strategy.ID()) comments = append(comments, fmt.Sprintf("%s:
%s", strategy.ShortName(), whyNot)) case Bet: triggeredStrategyIDs = append(triggeredStrategyIDs, strategy.ID()) var err error //var tip model.Tip //var tipPrice float64 tip := model.Tip{ SportID: int64(match.SportID), StrategyID: strategy.ID(), MatchID: match.MatchID, TipTime: time.Now().Unix(), ChampID: match.Champ.ChampID, ChampName: match.Champ.Name, MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName), Market: bet.Market, Side: bet.Side, Param: bet.Param, Price: bet.Price, CurrentMatchTime: upd.CurrentTime, OnexbetStatsMatchID: match.OnexbetStatsMatchID, IsTeamsSwapped: match.IsTeamsSwapped, } champRatings, ok := s.champRatings[match.SportID] if ok { // обновляем рейтинги чемпионатов key := ChampRatingKey{ ChampID: tip.ChampID, StrategyID: tip.StrategyID, } rating, ok := champRatings[key] if ok { //if (rating.Won+rating.Lost) >= 6 && rating.GetAccuracy() >= 75 { if rating.GetAccuracy() >= 70 { tip.IsRated = true } } } s.logger.Printf("Bet: %#v\n", tip) tip.TipID, err = s.model.AddTip(tip) if err != nil { s.logger.Printf("model.AddTip: %s\n", err) } else { // Отправить в websocket // Добавили новый Tip s.publisher.Publish(channel, WSMessageTipsChanged, nil) if match.SportID == flashscore.Football { // Для футбола только рейтинговые чемпионаты // Отправить в телеграм if strategy.IsNotifyInTelegram() && tip.IsRated { // Отправлять ли в телеграм msg := fmt.Sprintf(strategy.GetTelegramTipPattern(), tip.TipID, strategy.ID(), match.Zone.Name, match.Champ.Name, match.Home.CanonicalName, match.Away.CanonicalName, bet.Price) telegramChatID, hasChat := sportToTelegramChatID[match.SportID] if hasChat { err = sendMessageToTelegramGroup(telegramChatID, msg) if err != nil { s.logger.Printf("send tip to Telegram: %s\n", err) } } else { s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID) } } } else if match.SportID == flashscore.Handball { if strategy.IsNotifyInTelegram() && tip.IsRated { param, err := strconv.ParseFloat(bet.Param, 64) if err != nil { s.logger.Printf("Wrong bet param: %s; param=%s\n", err, bet.Param) } else { var betterParam1, betterParam2 float64 switch strategy.(type) { case HandballFTOver, HandballP1Over: betterParam1 = param - 1 betterParam2 = param - 2 case HandballFTUnder, HandballP1Under: betterParam1 = param + 1 betterParam2 = param + 2 default: panic(fmt.Sprintf("Unknown strategy %#v\n", strategy)) } // Для гандбола отправляем все прогнозы msg := fmt.Sprintf(strategy.GetTelegramTipPattern(), tip.TipID, strategy.ID(), match.Zone.Name, match.Champ.Name, match.Home.CanonicalName, match.Away.CanonicalName, param, bet.Price, param, betterParam1, betterParam2) telegramChatID, hasChat := sportToTelegramChatID[match.SportID] if hasChat { err = sendMessageToTelegramGroup(telegramChatID, msg) if err != nil { s.logger.Printf("send tip to Telegram: %s\n", err) } } else { s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID) } } } } else if match.SportID == flashscore.Tennis { if strategy.IsNotifyInTelegram() { msg := fmt.Sprintf(bet.TelegramMessage, tip.TipID) telegramChatID, hasChat := sportToTelegramChatID[match.SportID] if hasChat { err = sendMessageToTelegramGroup(telegramChatID, msg) if err != nil { s.logger.Printf("send tip to Telegram: %s\n", err) } } else { s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID) } } } } } } for _, strategyID := range triggeredStrategyIDs { delete(match.Strategies, strategyID) } if len(match.Strategies) == 0 { // Все стратегии сработали - отписываемся от матча s.logger.Printf("Unwatch: %d, %s\n", match.SportID, upd.MatchID) // Матч больше не интересен delete(s.onexbetMatchToTeamMatch, upd.MatchID) match.IsInplay = false s.onexbetAPIClient.Call(api.CallReq{ FuncName: "unwatch", In: onexbet.WatchReq{ SportID: flashscoreSportToOnexbetSport[match.SportID], MatchID: upd.MatchID, // onexbetMatchID }, }) } if match.SportID == flashscore.Tennis { if len(comments) > 0 { s.publisher.Publish( channel, WSMessageWhyNot, WhyNot{ MatchID: match.MatchID, Comment: strings.Join(comments, "

"), Time: "", HomeGoals: upd.HomeGoals, AwayGoals: upd.AwayGoals, GamePace: match.GamePace, GamePaceFrame: match.GamePaceFrame, }) } } else { if len(comments) > 0 { s.publisher.Publish( channel, WSMessageWhyNot, WhyNot{ MatchID: match.MatchID, Comment: strings.Join(comments, "

"), Time: fmt.Sprintf("%s", time.Duration(upd.CurrentTime)*time.Second), HomeGoals: upd.HomeGoals, AwayGoals: upd.AwayGoals, GamePace: match.GamePace, GamePaceFrame: match.GamePaceFrame, }) } } } /* var tipTextPattern string switch strategyID { case 1: tipTextPattern = tipTextAlgo1Pattern case 2: tipTextPattern = tipTextAlgo2Pattern case 3: tipTextPattern = tipTextAlgo3Pattern case 100: tipTextPattern = tipTextAlgo100Pattern } */ /* switch strategyID { case 1: var price float64 for _, over := range upd.H1.Total.Over { if over.Param == "0.5" { price = over.Price } } tipPrice = price tip = model.Tip{ SportID: SportFootball, StrategyID: int64(strategyID), MatchID: match.MatchID, TipTime: time.Now().Unix(), ChampName: match.Champ.Name, MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName), Market: MarketTotal1stHalf, Side: SideOver, Param: "0.5", Price: price, CurrentMatchTime: upd.CurrentTime, OnexbetStatsMatchID: match.OnexbetStatsMatchID, } case 2: var price float64 for _, over := range upd.Total.Over { if over.Param == "0.5" { price = over.Price } } tipPrice = price tip = model.Tip{ SportID: SportFootball, StrategyID: int64(strategyID), MatchID: match.MatchID, TipTime: time.Now().Unix(), ChampName: match.Champ.Name, MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName), Market: MarketTotal, Side: SideOver, Param: "0.5", Price: price, CurrentMatchTime: upd.CurrentTime, OnexbetStatsMatchID: match.OnexbetStatsMatchID, } case 3: var price float64 for _, over := range upd.Total.Over { if over.Param == "1.5" { price = over.Price } } tipPrice = price tip = model.Tip{ SportID: SportFootball, StrategyID: int64(strategyID), MatchID: match.MatchID, TipTime: time.Now().Unix(), ChampName: match.Champ.Name, MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName), Market: MarketTotal, Side: SideOver, Param: "1.5", Price: price, CurrentMatchTime: upd.CurrentTime, OnexbetStatsMatchID: match.OnexbetStatsMatchID, } case 100: var price float64 for _, over := range upd.H1.Total.Over { if over.Param == "0.5" { price = over.Price } } tipPrice = price tip = model.Tip{ SportID: SportFootball, StrategyID: int64(strategyID), MatchID: match.MatchID, TipTime: time.Now().Unix(), ChampName: match.Champ.Name, MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName), Market: MarketTotal1stHalf, Side: SideOver, Param: "0.5", Price: price, CurrentMatchTime: upd.CurrentTime, OnexbetStatsMatchID: match.OnexbetStatsMatchID, } } */