Files
tipper/daemon/over15.go
2026-07-21 05:29:37 +03:00

276 lines
5.8 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package daemon
/*
Футбольная стратегия.
ТБ 0.5 в 1м тайме
*/
import (
"fmt"
"gordenko.dev/dima/flashscore"
"gordenko.dev/dima/onexbet"
"gordenko.dev/dima/tipper/model"
)
/*
Алгоритм 3
ТБ 1.5 в Матче
До матча:
ТБ 2.5 (в матче) <=1.7
В 75% игр был гол
КФ фаворита <=1.4
В Лайве:
Сумма атак обычных и опасных >= 125
6 ударов в сторону ворот
4 удара в створ
До 70 минуты
*/
type Over15 struct {
id int64
notifyInTelegram bool
isChampAccepted func(string) bool
}
func NewOver15(opt StrategyOptions) Over15 {
if opt.ID == 0 {
panic("StrategyID not defined")
}
s := Over15{}
s.id = opt.ID
s.notifyInTelegram = opt.NotifyInTelegram
s.isChampAccepted = opt.IsChampAccepted
return s
}
func (s Over15) ID() int64 {
return s.id
}
func (s Over15) ShortName() string {
return fmt.Sprintf("#%d FT Over 1.5", s.id)
}
func (s Over15) IsNotifyInTelegram() bool {
return s.notifyInTelegram
}
func (s Over15) GetTelegramTipPattern() string {
return `Сигнал # %d.
Будет 2й ГОЛ!
Алгоритм %d
Тотал Больше 1.5
Футбол. %s. %s
%s - %s
Коэф. %.3f`
}
type isInterestingNotesOver15 struct {
PriceOver25 float64 `json:"Over 2.5 price"`
MatchesAnalysed int `json:"matchesAnalysed"`
HasGoalInMatches int `json:"hasGoalInMatches"`
GoalsPercent float64 `json:"goalsPercent"`
FavoritePrice float64 `json:"favoritePrice"`
}
func (s Over15) IsInteresting(report *TeamMatch) (notes interface{}, _ bool) {
var favoritePrice float64 = 2
for _, offer := range report.Odds.Winner {
if offer.Home < favoritePrice && offer.Home > 1.01 {
favoritePrice = offer.Home
}
if offer.Away < favoritePrice && offer.Away > 1.01 {
favoritePrice = offer.Away
}
}
if favoritePrice > 1.4 {
return
}
var (
priceOver25 float64
foundPriceOver25 bool
)
for _, total := range report.Odds.FullTimeTotal {
if total.Total != "2.5" {
continue
}
// 2.5
for _, offer := range total.Offers {
if offer.Bookmaker == flashscore.Bookmaker1xBet {
priceOver25 = offer.Over
foundPriceOver25 = true
break
}
}
if foundPriceOver25 {
break
} else {
// 1xBet не нашли
// Берем первый коэф.
if len(total.Offers) > 0 {
priceOver25 = total.Offers[0].Over
foundPriceOver25 = true
}
break
}
}
if priceOver25 > 1.7 {
return
}
var (
matchCount int
hasGoalsInMatchCount int
)
for _, match := range report.HomeTeamMatches {
if match.HomeGoals > 0 || match.AwayGoals > 0 {
hasGoalsInMatchCount++
}
matchCount++
}
for _, match := range report.AwayTeamMatches {
if match.HomeGoals > 0 || match.AwayGoals > 0 {
hasGoalsInMatchCount++
}
matchCount++
}
for _, match := range report.H2H {
if match.HomeGoals > 0 || match.AwayGoals > 0 {
hasGoalsInMatchCount++
}
matchCount++
}
if matchCount == 0 {
return
}
// matchCount - 100%
// goalsInMatchCount - x%
goalsPercent := float64(hasGoalsInMatchCount*100) / float64(matchCount)
if goalsPercent < 75 {
return
}
obj := isInterestingNotesOver15{
PriceOver25: priceOver25,
MatchesAnalysed: matchCount,
HasGoalInMatches: hasGoalsInMatchCount,
GoalsPercent: goalsPercent,
FavoritePrice: favoritePrice,
}
//buf, _ := json.MarshalIndent(obj, "", " ")
return obj, true
}
func (s Over15) GetTip(match *TeamMatch, upd onexbet.TeamLiveMatchData) (_ string, _ *BetDetails, _ TipCode) {
if upd.CurrentTime == 0 {
// ВАЖНО!
// Матч еще не начался. Избегаем деления на 0 при вычислении attacksRatio
return "матч не начался", nil, Waiting
}
// Прогнозы даем до 70 минуты включительно.
maxTime := 70 * 60
if upd.CurrentTime > maxTime {
return "70 минут уже отыграли", nil, Unwatch
}
goals := upd.HomeGoals + upd.AwayGoals
if goals > 1 {
// Если 2 гола уже забили - выходим
return "уже забили более 1 гола", nil, Unwatch
}
if goals == 0 {
return "счет 0:0", nil, Waiting
}
// Ищем тотал Больше 1.5
// Минимальный курс
minPrice := 1.5
var (
minPriceCheckPassed bool
currentPrice float64
)
for _, over := range upd.Total.Over {
if over.Param == "1.5" {
if over.Price < minPrice {
return fmt.Sprintf("коэф. %.2f < %.2f", over.Price, minPrice), nil, Waiting
}
currentPrice = over.Price
minPriceCheckPassed = true
break
}
}
if !minPriceCheckPassed {
return "тотал 1.5 не найден", nil, Waiting
}
//
attacks := upd.HomeAttacks + upd.AwayAttacks + upd.HomeDangerousAttacks + upd.AwayDangerousAttacks
shotsOffTarget := upd.HomeShotsOffTarget + upd.AwayShotsOffTarget
shotsOnTarget := upd.HomeShotsOnTarget + upd.AwayShotsOnTarget
if attacks < 125 {
return fmt.Sprintf("%d атак < 125", attacks), nil, Waiting
}
if shotsOffTarget < 6 {
return fmt.Sprintf("%d shotsOffTarget < 6", shotsOffTarget), nil, Waiting
}
if shotsOnTarget < 4 {
return fmt.Sprintf("%d shotsOnTarget < 4", shotsOnTarget), nil, Waiting
}
return "", &BetDetails{
Market: MarketTotal,
Side: SideOver,
Param: "1.5",
Price: currentPrice,
}, Bet
}
func (s Over15) GetResult(tip model.Tip, stats onexbet.TeamMatchResult) (_ *TipResult) {
//buf, _ := json.MarshalIndent(stats, "", " ")
//fmt.Printf("%s\n", buf)
if stats.Status != onexbet.StatusMatchCompleted {
return
}
res := new(TipResult)
goals := stats.HomePoints + stats.AwayPoints
if goals > 1 {
res.Status = model.Won
} else {
res.Status = model.Lost
}
res.Result = fmt.Sprintf("счет: %d-%d", stats.HomePoints, stats.AwayPoints)
return res
}