├── README.md ├── LICENSE ├── bot.py └── predict.py /README.md: -------------------------------------------------------------------------------- 1 | predicts soccer match results using poisson regression, just for educational cutesy purposes. pls don't use it to bet on matches, it may upset you 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ümit Kaan Usta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import time 4 | 5 | TOKEN = "insert_token" 6 | URL = "https://api.telegram.org/bot{}/".format(TOKEN) 7 | 8 | 9 | def check_connection(url): 10 | try: 11 | _ = requests.get(url, timeout=5) 12 | return True 13 | except requests.ConnectionError: 14 | print("No connection") 15 | return False 16 | 17 | 18 | def get_url(url): 19 | response = requests.get(url) 20 | content = response.content.decode("utf8") 21 | return content 22 | 23 | 24 | def get_json(url): 25 | content = get_url(url) 26 | js = json.loads(content) 27 | return js 28 | 29 | 30 | def get_updates(): 31 | url = URL + "getUpdates" 32 | js = get_json(url) 33 | return js 34 | 35 | 36 | def get_users(updates): 37 | # We get the id's of every user to send them messages 38 | num_updates = len(updates["result"]) 39 | id_list = list(set([updates["result"][i]["message"]["chat"]["id"] for i in range(num_updates)])) 40 | return id_list 41 | 42 | 43 | def broadcast(id_list, message): 44 | # Send the message 45 | for user_id in id_list: 46 | url = URL + "sendMessage?text={}&chat_id={}".format(message, user_id) 47 | get_url(url) 48 | 49 | 50 | def send_message(user_id, message): 51 | url = URL + "sendMessage?text={}&chat_id={}".format(message, user_id) 52 | get_url(url) 53 | 54 | 55 | def show_bets(updates, text): 56 | last_text = updates["result"][-1]["message"]["text"] 57 | user_id = updates["result"][-1]["message"]["chat"]["id"] 58 | if last_text == "/kupon" and len(updates["result"]) > 0: 59 | send_message(user_id, text) 60 | time.sleep(15) -------------------------------------------------------------------------------- /predict.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from scipy.stats import poisson 4 | import statsmodels.api as sm 5 | import statsmodels.formula.api as smf 6 | import bot 7 | import random 8 | 9 | 10 | def simulate_match(model, home, away, max_goals=10): 11 | home_goals_avg = model.predict(pd.DataFrame(data={"scoring": home, "conceding": away, "home_status": 1}, 12 | index=[0])) 13 | away_goals_avg = model.predict(pd.DataFrame(data={"scoring": away, "conceding": home, "home_status": 0}, 14 | index=[0])) 15 | predictions = [[poisson.pmf(i, team_avg) for i in range(0, max_goals + 1)] 16 | for team_avg in [home_goals_avg, away_goals_avg]] 17 | return np.outer(np.array(predictions[0]), np.array(predictions[1])) 18 | 19 | 20 | def fill_test_df(test_df): 21 | home_teams = [] 22 | away_teams = [] 23 | pred_home = [] 24 | pred_away = [] 25 | 26 | for n in range(0, len(test_df["HomeTeam"])): 27 | sim = simulate_match(poisson_model, test_df["HomeTeam"].loc[n], test_df["AwayTeam"].loc[n], 28 | max_goals=10) 29 | unraveled = np.unravel_index(sim.argmax(), sim.shape) 30 | 31 | home_teams.append(test_df["HomeTeam"].loc[n]) 32 | away_teams.append(test_df["AwayTeam"].loc[n]) 33 | pred_home.append(unraveled[0]) 34 | pred_away.append(unraveled[1]) 35 | 36 | test_df = pd.DataFrame({"HomeTeam": home_teams, "AwayTeam": away_teams, 37 | "HomePredicted": pred_home, "AwayPredicted": pred_away}) 38 | return test_df 39 | 40 | 41 | def transform_df(test_df): 42 | test_df["HomeScore"] = test_df["HomePredicted"].round(0).astype(int) 43 | test_df["AwayScore"] = test_df["AwayPredicted"].round(0).astype(int) 44 | test_df.loc[(test_df["HomeScore"] > test_df["AwayScore"]), "1x2_Pred"] = "1" 45 | test_df.loc[(test_df["HomeScore"] == test_df["AwayScore"]), "1x2_Pred"] = "X" 46 | test_df.loc[(test_df["HomeScore"] < test_df["AwayScore"]), "1x2_Pred"] = "2" 47 | return test_df 48 | 49 | 50 | def to_string(predicted_matches): 51 | final_string = "Kupon oluşturuluyor...\n" 52 | pred_list = [] 53 | for i in range(13): 54 | match = str(predicted_matches["HomeTeam"][i]) + " - " + str(predicted_matches["AwayTeam"][i]) \ 55 | + " MS " + predicted_matches["1x2_Pred"][i] + "\n" 56 | pred_list.append(match) 57 | choice_list = random.sample(pred_list, k=4) 58 | for string in choice_list: 59 | final_string += string 60 | final_string += "Tekrar kupon almak için 15 saniye bekleyin, ardından /kupon komutunu tekrar kullanın." 61 | return final_string 62 | 63 | 64 | def main(): 65 | on = True 66 | while on: 67 | initial_length = len(bot.get_updates()["result"]) 68 | text = to_string(predicted_transformed) 69 | if len(bot.get_updates()["result"]) > initial_length: 70 | bot.show_bets(bot.get_updates(), text) 71 | continue 72 | """user_ids = get_users(get_updates()) 73 | send = int(input("Broadcast (1)")) 74 | if send == 1: 75 | text = input("Text: ") 76 | broadcast(user_ids, text) 77 | else: 78 | on = False""" 79 | 80 | 81 | # Preparing the data 82 | stsl = "https://fixturedownload.com/download/super-lig-2019-TurkeyStandardTime.csv" 83 | 84 | df_stsl = pd.read_csv(stsl) 85 | df_stsl = df_stsl.rename(columns={"Home Team": "HomeTeam", "Away Team": "AwayTeam"}) 86 | df_stsl = df_stsl.loc[df_stsl["Result"].notnull()] 87 | 88 | df_stsl["HomeGoals"] = df_stsl.Result.str[0].astype(int) 89 | df_stsl["AwayGoals"] = df_stsl.Result.str[4].astype(int) 90 | df_stsl = df_stsl[["HomeTeam", "AwayTeam", "HomeGoals", "AwayGoals"]] 91 | # print(df_stsl.head(20)) 92 | 93 | df_stsl_fix = pd.read_csv(stsl) 94 | df_stsl_fix = df_stsl_fix.rename(columns={"Home Team": "HomeTeam", "Away Team": "AwayTeam"}) 95 | df_stsl_fix = df_stsl_fix.loc[df_stsl_fix["Result"].isnull()] 96 | df_stsl_fix = df_stsl_fix.reset_index()[["Round Number", "HomeTeam", "AwayTeam"]] 97 | # print(df_stsl_fix.head(20)) 98 | 99 | 100 | # Rearranging data, to make it suitable for the poisson model 101 | goal_data = pd.concat([df_stsl[["HomeTeam", "AwayTeam", "HomeGoals"]].assign(home_status=1).rename( 102 | columns={"HomeTeam": "scoring", "AwayTeam": "conceding", "HomeGoals": "goals"}), 103 | df_stsl[["AwayTeam", "HomeTeam", "AwayGoals"]].assign(home_status=0).rename( 104 | columns={"AwayTeam": "scoring", "HomeTeam": "conceding", "AwayGoals": "goals"})]) 105 | 106 | # scoring - shows the capability to score goals 107 | # conceding - shows the "capability" to concede goals 108 | poisson_model = smf.glm(formula="goals ~ home_status + scoring + conceding", 109 | data=goal_data, family=sm.families.Poisson()).fit() 110 | # print(poisson_model.summary()) 111 | 112 | predicted_fixture = fill_test_df(df_stsl_fix) 113 | predicted_transformed = transform_df(predicted_fixture) 114 | 115 | 116 | if __name__ == "__main__": 117 | main() 118 | --------------------------------------------------------------------------------