Compare commits

...
10 Commits
18 changed files with 244 additions and 73 deletions
+24
View File
@@ -0,0 +1,24 @@
# Python
__pycache__/
*.py[cod]
.venv/
venv/
env/
# Output from the scripts
*_ans.csv
*.log
# Secrets and local config
.env
.env.*
*.pem
*.key
secrets.py
# Editor junk
.vscode/
.idea/
*.swp
*~
.DS_Store
+18 -3
View File
@@ -4,8 +4,23 @@ THE WVLOTTOPY DEVELOPERS HAVE NO AFFILIATION WITH THE WEST VIRGINIA STATE LOTTER
This script generates the most likely lottery numbers based off frequency of winning numbers.
Previously there were records dating back to 1992 that were removed by the website, which has lead me to rewrite and encourage the collaboration and sharing of this work. I will attach an excel file in the near future that includes the previous records and soon try to reincorperate them into the script. Originally excel functionality was stripped for performance.
Previously there were records dating back to 1992 that were removed by the website, which has lead me to rewrite and encourage the collaboration and sharing of this work. I have attached an excel file that includes the previous records. Originally excel functionality was stripped for performance but has been reimplemented.
I am welcoming anyone who wants to to port it to their own state/country to do so. I currently have a website www.wvlotterypredictor.xyz hosting my numbers to be refreshed daily. Collaboration and suggestion to a more accurate algorithm is also welcome. I can be contacted about the project through my site email, on here, or on the Twitter linked on my site.
# How the site works
- Each game has its own script. It pulls every past draw from the WV Lottery results api (the same one wvlottery.com uses for its past draws page), adds the older records from the excel files where there are any, and counts how often each number has been drawn.
- On the site the scripts write their numbers to a csv instead of printing them. cron runs each one about 45 minutes after that game's drawing so the new numbers are already posted.
- The site itself is Django served by gunicorn behind nginx. It reads the csv files for the home page and caches the page in redis, which gets cleared every hour.
# Good luck!
# CHANGELOG
- September 26th 2026: wvlottery.com was rebuilt and the old history tables are gone, so every script now pulls past draws from the json results api the new site uses. Added Cash Pop. Updated Mega Millions odds for the 2025 changes.
- June 29th 2022: Added support for old data that was previously scrubbed from the lottery site. It is more accurate and includes more data than the previous one. Chance for daily3 is now bugged however due to the large amount of numbers and dates. This will be fixed soon.
# TODO:
- Correct chance numbers for Daily3
I am welcoming anyone who wants to to port it to their own state/country to do so. I currently have a website www.wvlotterypredictor.xyz hosting my numbers to be refreshed daily. Collaboration and suggestion to a more accurate algorithm is also welcome.
#Good luck!
+23 -10
View File
@@ -4,19 +4,32 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/cash-25/?game-analyze=cash-25&what-to-search=historysearch&date-range=-1'
# old data from WVLottery.com
df_old = pd.read_excel('./excel_lotto_records/cash25.xlsx')
salvaged = df_old[['Date', 'Numbers']]
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=10&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
df = pd.concat([dfs[0], salvaged], ignore_index=True)
df2 = df[['Date', 'Numbers']]
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
@@ -36,10 +49,10 @@ for n in range(0, 25):
likely_nums = [v[0] for v in most_common]
frequency = [v[-1] for v in most_common]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency)
Chance = frac(total_freq, 177100) # Chance = number call freq / all possible numbers i.e. 177100
Winning_Numbers = str("-".join(sorted_nums))
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers} \n"
print(f"Likely numbers are . . . {Forecast} \n"
f"With percent chance of winning being {Chance}")
+48
View File
@@ -0,0 +1,48 @@
# WVLottopy: Matteo DiBiagio
from fractions import Fraction as frac
import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=24&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
}
# Get web data, cash pop draws every 15 min so only use the last ~3000 draws (about a month)
web = {'Date': [], 'Numbers': []}
page = 0
while page < 6:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
if data['last']:
break
page += 1
df2 = pd.DataFrame(web)
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
return date, nums
date, nums = get_data()
# Formatting
hyphenfree = []
for x in nums:
hyphenfree.append(x.replace('–',', '))
splitlist = ", ".join(hyphenfree)
sep = splitlist.split(", ")
for n in range(0, 15):
most_common= Counter(sep).most_common(3)
likely_nums = [v[0] for v in most_common]
frequency = [v[-1] for v in most_common]
Forecast = likely_nums[0]
Backups = str(" - ".join(likely_nums[1:]))
Chance = frac(1, 15) # Only one number is drawn out of 15 so every pick has the same chance
print(f"Likely number is . . . {Forecast} Backups: {Backups}\n"
f"With percent chance of winning being {Chance}")
+21 -10
View File
@@ -4,15 +4,25 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/daily-3/?game-analyze=daily-3&what-to-search=historysearch&date-range=1'
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=9&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
@@ -35,10 +45,11 @@ for n in range(0, 10):
likely_nums = [v[0] for v in most_common]
frequency = [v[-1] for v in most_common]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency)
Chance = frac(total_freq, 1000) # Chance = number call freq / all possible numbers i.e. 1000
Winning_Numbers = str("-".join(sorted_nums))
Chance = frac(total_freq, 15000) # Chance = number call freq / all possible numbers i.e. 1000
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers} \n"
f"With percent chance of winning being {Chance}")
print(f"Likely numbers are . . . {Forecast} \n"
f"With percent chance of winning being {Chance} \n"
f"DISCLAIMER: This set's chance is innacurate due to how many numbers are drawn per day.")
+23 -9
View File
@@ -4,18 +4,32 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/daily-4/?game-analyze=daily-4&what-to-search=historysearch&date-range=-1'
# Old data from WVLottery.com
df_old = pd.read_excel('./excel_lotto_records/daily4.xlsx')
salvaged = df_old[['Date', 'Numbers']]
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=14&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
df = pd.concat([dfs[0], salvaged], ignore_index=True)
df2 = df[['Date', 'Numbers']]
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
@@ -35,10 +49,10 @@ for n in range(0, 9):
likely_nums = [v[0] for v in most_common]
frequency = [v[-1] for v in most_common]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency)
Chance = frac(total_freq, 10000) # Chance = number call freq / all possible numbers i.e. 10000
Winning_Numbers = str("-".join(sorted_nums))
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers}, \n"
print(f"Likely numbers are . . . {Forecast} \n"
f"With percent chance of winning being {Chance}")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+24 -11
View File
@@ -4,20 +4,33 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/lotto-america/?game-analyze=lotto-america&what-to-search=historysearch&date-range=-1'
df_old = pd.read_excel('./excel_lotto_records/lotto_america.xlsx')
salvaged = df_old[['Date', 'Numbers', 'SB']]
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=16&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': [], 'SB': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
web['SB'].append([n['data'] for n in x['resultData'] if n['type'] == 'SPECIAL'][0])
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
df2 = df[['Date', 'Numbers', 'SB', 'All Star']]
df = pd.concat([dfs[0], salvaged], ignore_index=True)
df2 = df[['Date', 'Numbers', 'SB']]
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
SBs = list(df2['SB'].astype('int'))
@@ -42,10 +55,10 @@ for n in range(0, 10):
SB = [v[0] for v in most_common_sb]
frequency_sb = [v[-1] for v in most_common_sb]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency + frequency_sb)
Chance = frac(total_freq, 25989600) # Chance = number call freq / all possible numbers i.e. 25,989,600
Winning_Numbers = str("-".join(sorted_nums))
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers} SB: {SB}\n"
print(f"Likely numbers are . . . {Forecast} SB: {SB}\n"
f"With percent chance of winning being {Chance}")
+26 -10
View File
@@ -4,19 +4,35 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/powerball/?game-analyze=powerball&what-to-search=historysearch&date-range=-1'
# previous records which have since been removed from wvlottery.com's database
df_old = pd.read_excel('./excel_lotto_records/lotto.xlsx')
salvaged = df_old[['Date', 'Numbers', 'PB']]
# Current web records
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=12&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': [], 'PB': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
web['PB'].append([n['data'] for n in x['resultData'] if n['type'] == 'SPECIAL'][0])
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
df2 = df[['Date', 'Numbers', 'PB', 'PPX', 'Winners WV Only', 'Payout WV Only']]
df = pd.concat([dfs[0], salvaged], ignore_index=True)
df2 = df[['Date', 'Numbers', 'PB']]
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
PBs = list(df2['PB'].astype('int'))
@@ -41,10 +57,10 @@ for n in range(0, 26):
PB = [v[0] for v in most_common_pb]
frequency_pb = [v[-1] for v in most_common_pb]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency + frequency_pb)
Chance = frac(total_freq, 292201338) # Chance = number call freq / all possible numbers i.e. 292201338
Winning_Numbers = str("-".join(sorted_nums))
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers} PB: {PB}\n"
print(f"Likely numbers are . . . {Forecast} PB: {PB}\n"
f"With percent chance of winning being {Chance}")
+26 -12
View File
@@ -4,20 +4,34 @@ import pandas as pd
import requests
from collections import Counter
def get_data():
url = 'https://wvlottery.com/draw-games/mega-millions/?game-analyze=mega-millions&what-to-search=historysearch&date-range=-1'
# previous records which have since been removed from wvlottery.com's database
df_old = pd.read_excel('./excel_lotto_records/lotto_megamil.xlsx')
salvaged = df_old[['Date', 'Numbers', 'MB']]
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=20&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
header = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
# Get web data
r = requests.get(url, headers=header)
dfs = pd.read_html(r.text)
# Get web data, the new site pulls past draws from json 500 at a time
web = {'Date': [], 'Numbers': [], 'MB': []}
page = 0
while True:
r = requests.get(url + str(page), headers=header)
data = r.json()
for x in data['content']:
web['Date'].append(x['drawingDate'])
web['Numbers'].append('–'.join(str(n['data']) for n in x['resultData'] if n['type'] == 'REGULAR'))
web['MB'].append([n['data'] for n in x['resultData'] if n['type'] == 'SPECIAL'][0])
if data['last']:
break
page += 1
dfs = [pd.DataFrame(web)]
pd.set_option('display.max_rows', None)
# Specifies no max rows, otherwise only shows 10 records
df = dfs[0]
df2 = df[['Date', 'Numbers', 'MB', 'MP']]
df = pd.concat([dfs[0], salvaged], ignore_index=True)
df2 = df[['Date', 'Numbers', 'MB']]
date = list(df2['Date'])
nums = list(df2['Numbers'].astype('str'))
MBs = list(df2['MB'].astype('int'))
@@ -42,10 +56,10 @@ for n in range(0, 25):
MB = [v[0] for v in most_common_mb]
frequency_mb = [v[-1] for v in most_common_mb]
sorted_nums = sorted(likely_nums)
sorted_nums = sorted(likely_nums, key=lambda x: (len(x), x))
total_freq = sum(frequency + frequency_mb)
Chance = frac(total_freq, 302575350) # Chance = number call freq / all possible numbers i.e. 11238513
Winning_Numbers = str("-".join(sorted_nums))
Chance = frac(total_freq, 290472336) # Chance = number call freq / all possible numbers i.e. 290472336
Forecast = str(" - ".join(sorted_nums))
print(f"Likely numbers are . . . {Winning_Numbers} MB: {MB}\n"
print(f"Likely numbers are . . . {Forecast} MB: {MB}\n"
f"With percent chance of winning being {Chance}")
+2 -1
View File
@@ -1,2 +1,3 @@
pandas==1.3.5
requests==2.26.0
requests==2.26.0
openpyxl
+9 -7
View File
@@ -4,15 +4,17 @@
# MIT License
# Edit to your need
echo "Powerball" &&
echo "<--------> Powerball <-------->" &&
python lottopy_pb.py &&
echo "MegaMillions" &&
echo "<--------> MegaMillions <-------->" &&
python megamil.py &&
echo "Lotto America" &&
echo "<--------> Lotto America <-------->" &&
python lotto_america.py &&
echo "Daily3" &&
echo "<--------> Daily3 <-------->" &&
python daily3.py &&
echo "Daily4" &&
echo "<--------> Daily4 <-------->" &&
python daily4.py &&
echo "Cash25" &&
python cash25.py
echo "<--------> Cash25 <-------->" &&
python cash25.py &&
echo "<--------> Cash Pop <-------->" &&
python cashpop.py