Compare commits
14
Commits
8e20f1d7aa
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
932c6fb08b | ||
|
|
01ed0d194b | ||
|
|
1037813a3f | ||
|
|
542e57de34 | ||
|
|
ea275b3f82 | ||
|
|
d920dd9724 | ||
|
|
3f9f7122d8 | ||
|
|
331be7d33b | ||
|
|
155844172f | ||
|
|
05a82a9910 | ||
|
|
60e3bbeb2f | ||
|
|
fe831750d3 | ||
|
|
de1d4c9255 | ||
|
|
ef4d647110 |
+24
@@ -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
|
||||||
@@ -4,8 +4,18 @@ 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.
|
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 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. The chance shown is the actual odds of that ticket hitting, every ticket has the same odds so the forecast is just going with the numbers that have been called the most.
|
||||||
|
- 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!
|
# 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.
|
||||||
|
- September 26th 2026 (later): The excel records were never actually getting counted (they use - and the site used –), they are now. Numbers that cant be drawn anymore since the ball ranges changed get skipped. Chance is now the real odds of the forecast ticket winning instead of the frequency number, Daily3 and Daily4 are the odds for a box play.
|
||||||
|
- 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.
|
||||||
|
|||||||
@@ -1,22 +1,36 @@
|
|||||||
# WVLottopy: Matteo DiBiagio
|
# WVLottopy: Matteo DiBiagio
|
||||||
from fractions import Fraction as frac
|
from fractions import Fraction as frac
|
||||||
|
from math import comb
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
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 = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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, the new site pulls past draws from json 500 at a time
|
||||||
# Get web data
|
web = {'Date': [], 'Numbers': []}
|
||||||
r = requests.get(url, headers=header)
|
page = 0
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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']]
|
df2 = df[['Date', 'Numbers']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
@@ -25,21 +39,26 @@ def get_data():
|
|||||||
date, nums = get_data()
|
date, nums = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only count numbers that can still be called, the ball ranges have changed over the years
|
||||||
|
# so the old records have some numbers that dont exist in the game anymore
|
||||||
|
sep = [x for x in sep if x.isdigit() and 1 <= int(x) <= 25]
|
||||||
|
|
||||||
for n in range(0, 25):
|
for n in range(0, 25):
|
||||||
most_common= Counter(sep).most_common(6)
|
most_common= Counter(sep).most_common(6)
|
||||||
likely_nums = [v[0] for v in most_common]
|
likely_nums = [v[0] for v in most_common]
|
||||||
frequency = [v[-1] 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 = 1 / every possible ticket, 25 choose 6 = 177100
|
||||||
Chance = frac(total_freq, 177100) # Chance = number call freq / all possible numbers i.e. 177100
|
# every ticket has the same odds, the forecast just goes with the numbers that get called the most
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(1, comb(25, 6))
|
||||||
|
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}")
|
f"With percent chance of winning being {Chance}")
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
# 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(", ")
|
||||||
|
# Only keep 1 - 15, just in case anything weird comes back from the site
|
||||||
|
sep = [x for x in sep if x.isdigit() and 1 <= int(x) <= 15]
|
||||||
|
|
||||||
|
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}")
|
||||||
@@ -4,18 +4,32 @@ import pandas as pd
|
|||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
def get_data():
|
||||||
url = 'https://wvlottery.com/draw-games/daily-3/?game-analyze=daily-3&what-to-search=historysearch&date-range=1'
|
# Old records from the excel sheets, wvlottery.com took these down but they go back to the early 90s on some games
|
||||||
|
df_old = pd.read_excel('./excel_lotto_records/daily3.xlsx')
|
||||||
|
salvaged = df_old[['Date', 'Numbers']]
|
||||||
|
|
||||||
|
url = 'https://gateway.loyalty.wvlottery.com/services/jackpot/api/v1/jackpot-results?gameId=9&jackpotStatus=PAYABLE&size=500&sort=externalId,drawDate,desc&page='
|
||||||
header = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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
|
# Get web data, the new site pulls past draws from json 500 at a time
|
||||||
r = requests.get(url, headers=header)
|
web = {'Date': [], 'Numbers': []}
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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']]
|
df2 = df[['Date', 'Numbers']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
@@ -24,21 +38,25 @@ def get_data():
|
|||||||
date, nums = get_data()
|
date, nums = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only keep actual digits, gets rid of any blanks from the excel records
|
||||||
|
sep = [x for x in sep if x.isdigit() and int(x) <= 9]
|
||||||
|
|
||||||
for n in range(0, 10):
|
for n in range(0, 10):
|
||||||
most_common= Counter(sep).most_common(3)
|
most_common= Counter(sep).most_common(3)
|
||||||
likely_nums = [v[0] for v in most_common]
|
likely_nums = [v[0] for v in most_common]
|
||||||
frequency = [v[-1] 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 = playing the forecast as a box (any order), 3 different digits can come up 6 ways out of 1000 = 3/500
|
||||||
Chance = frac(total_freq, 1000) # Chance = number call freq / all possible numbers i.e. 1000
|
# playing it straight (exact order) is 1/1000
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(6, 1000)
|
||||||
|
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}")
|
f"With percent chance of winning being {Chance}")
|
||||||
@@ -4,18 +4,32 @@ import pandas as pd
|
|||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
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 = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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
|
# Get web data, the new site pulls past draws from json 500 at a time
|
||||||
r = requests.get(url, headers=header)
|
web = {'Date': [], 'Numbers': []}
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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']]
|
df2 = df[['Date', 'Numbers']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
@@ -24,21 +38,25 @@ def get_data():
|
|||||||
date, nums = get_data()
|
date, nums = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only keep actual digits, gets rid of any blanks from the excel records
|
||||||
|
sep = [x for x in sep if x.isdigit() and int(x) <= 9]
|
||||||
|
|
||||||
for n in range(0, 9):
|
for n in range(0, 9):
|
||||||
most_common= Counter(sep).most_common(4)
|
most_common= Counter(sep).most_common(4)
|
||||||
likely_nums = [v[0] for v in most_common]
|
likely_nums = [v[0] for v in most_common]
|
||||||
frequency = [v[-1] 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 = playing the forecast as a box (any order), 4 different digits can come up 24 ways out of 10000 = 3/1250
|
||||||
Chance = frac(total_freq, 10000) # Chance = number call freq / all possible numbers i.e. 10000
|
# playing it straight (exact order) is 1/10000
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(24, 10000)
|
||||||
|
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}")
|
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.
+35
-14
@@ -1,23 +1,38 @@
|
|||||||
# WVLottopy: Matteo DiBiagio
|
# WVLottopy: Matteo DiBiagio
|
||||||
from fractions import Fraction as frac
|
from fractions import Fraction as frac
|
||||||
|
from math import comb
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
def get_data():
|
||||||
url = 'https://wvlottery.com/draw-games/lotto-america/?game-analyze=lotto-america&what-to-search=historysearch&date-range=-1'
|
# Old records from the excel sheets, wvlottery.com took these down but they go back to the early 90s on some games
|
||||||
|
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 = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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, the new site pulls past draws from json 500 at a time
|
||||||
# Get web data
|
web = {'Date': [], 'Numbers': [], 'SB': []}
|
||||||
r = requests.get(url, headers=header)
|
page = 0
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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', 'SB', 'All Star']]
|
df2 = df[['Date', 'Numbers', 'SB']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
SBs = list(df2['SB'].astype('int'))
|
SBs = list(df2['SB'].astype('int'))
|
||||||
@@ -26,11 +41,16 @@ def get_data():
|
|||||||
date, nums, SBs = get_data()
|
date, nums, SBs = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only count numbers that can still be called, the ball ranges have changed over the years
|
||||||
|
# so the old records have some numbers that dont exist in the game anymore
|
||||||
|
sep = [x for x in sep if x.isdigit() and 1 <= int(x) <= 52]
|
||||||
|
SBs = [x for x in SBs if 1 <= x <= 10]
|
||||||
|
|
||||||
for n in range(0, 52):
|
for n in range(0, 52):
|
||||||
most_common= Counter(sep).most_common(5)
|
most_common= Counter(sep).most_common(5)
|
||||||
@@ -42,10 +62,11 @@ for n in range(0, 10):
|
|||||||
SB = [v[0] for v in most_common_sb]
|
SB = [v[0] for v in most_common_sb]
|
||||||
frequency_sb = [v[-1] 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 = 1 / every possible ticket, 52 choose 5 white balls times 10 star balls = 25989600
|
||||||
Chance = frac(total_freq, 25989600) # Chance = number call freq / all possible numbers i.e. 25,989,600
|
# every ticket has the same odds, the forecast just goes with the numbers that get called the most
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(1, comb(52, 5) * 10)
|
||||||
|
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}")
|
f"With percent chance of winning being {Chance}")
|
||||||
|
|||||||
+36
-13
@@ -1,22 +1,39 @@
|
|||||||
# WVLottopy: Matteo DiBiagio
|
# WVLottopy: Matteo DiBiagio
|
||||||
from fractions import Fraction as frac
|
from fractions import Fraction as frac
|
||||||
|
from math import comb
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
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 = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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
|
# Get web data, the new site pulls past draws from json 500 at a time
|
||||||
r = requests.get(url, headers=header)
|
web = {'Date': [], 'Numbers': [], 'PB': []}
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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', 'PB', 'PPX', 'Winners WV Only', 'Payout WV Only']]
|
df2 = df[['Date', 'Numbers', 'PB']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
PBs = list(df2['PB'].astype('int'))
|
PBs = list(df2['PB'].astype('int'))
|
||||||
@@ -25,11 +42,16 @@ def get_data():
|
|||||||
date, nums, PBs = get_data()
|
date, nums, PBs = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only count numbers that can still be called, the ball ranges have changed over the years
|
||||||
|
# so the old records have some numbers that dont exist in the game anymore
|
||||||
|
sep = [x for x in sep if x.isdigit() and 1 <= int(x) <= 69]
|
||||||
|
PBs = [x for x in PBs if 1 <= x <= 26]
|
||||||
|
|
||||||
for n in range(0, 69):
|
for n in range(0, 69):
|
||||||
most_common = Counter(sep).most_common(5)
|
most_common = Counter(sep).most_common(5)
|
||||||
@@ -41,10 +63,11 @@ for n in range(0, 26):
|
|||||||
PB = [v[0] for v in most_common_pb]
|
PB = [v[0] for v in most_common_pb]
|
||||||
frequency_pb = [v[-1] 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 = 1 / every possible ticket, 69 choose 5 white balls times 26 powerballs = 292201338
|
||||||
Chance = frac(total_freq, 292201338) # Chance = number call freq / all possible numbers i.e. 292201338
|
# every ticket has the same odds, the forecast just goes with the numbers that get called the most
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(1, comb(69, 5) * 26)
|
||||||
|
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}")
|
f"With percent chance of winning being {Chance}")
|
||||||
+35
-14
@@ -1,23 +1,38 @@
|
|||||||
# WVLottopy megamil: Matteo DiBiagio
|
# WVLottopy megamil: Matteo DiBiagio
|
||||||
from fractions import Fraction as frac
|
from fractions import Fraction as frac
|
||||||
|
from math import comb
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import requests
|
import requests
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
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 = {
|
header = {
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36",
|
"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, the new site pulls past draws from json 500 at a time
|
||||||
# Get web data
|
web = {'Date': [], 'Numbers': [], 'MB': []}
|
||||||
r = requests.get(url, headers=header)
|
page = 0
|
||||||
dfs = pd.read_html(r.text)
|
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)
|
pd.set_option('display.max_rows', None)
|
||||||
# Specifies no max rows, otherwise only shows 10 records
|
# 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', 'MB', 'MP']]
|
df2 = df[['Date', 'Numbers', 'MB']]
|
||||||
date = list(df2['Date'])
|
date = list(df2['Date'])
|
||||||
nums = list(df2['Numbers'].astype('str'))
|
nums = list(df2['Numbers'].astype('str'))
|
||||||
MBs = list(df2['MB'].astype('int'))
|
MBs = list(df2['MB'].astype('int'))
|
||||||
@@ -26,11 +41,16 @@ def get_data():
|
|||||||
date, nums, MBs = get_data()
|
date, nums, MBs = get_data()
|
||||||
|
|
||||||
# Formatting
|
# Formatting
|
||||||
|
# Site numbers come split by – and the excel records by - so it splits on both
|
||||||
hyphenfree = []
|
hyphenfree = []
|
||||||
for x in nums:
|
for x in nums:
|
||||||
hyphenfree.append(x.replace('–',', '))
|
hyphenfree.append(x.replace('–',', ').replace('-',', '))
|
||||||
splitlist = ", ".join(hyphenfree)
|
splitlist = ", ".join(hyphenfree)
|
||||||
sep = splitlist.split(", ")
|
sep = splitlist.split(", ")
|
||||||
|
# Only count numbers that can still be called, the ball ranges have changed over the years
|
||||||
|
# so the old records have some numbers that dont exist in the game anymore
|
||||||
|
sep = [x for x in sep if x.isdigit() and 1 <= int(x) <= 70]
|
||||||
|
MBs = [x for x in MBs if 1 <= x <= 24]
|
||||||
|
|
||||||
for n in range(0, 70):
|
for n in range(0, 70):
|
||||||
most_common= Counter(sep).most_common(5)
|
most_common= Counter(sep).most_common(5)
|
||||||
@@ -42,10 +62,11 @@ for n in range(0, 25):
|
|||||||
MB = [v[0] for v in most_common_mb]
|
MB = [v[0] for v in most_common_mb]
|
||||||
frequency_mb = [v[-1] 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 = 1 / every possible ticket, 70 choose 5 white balls times 24 mega balls = 290472336
|
||||||
Chance = frac(total_freq, 302575350) # Chance = number call freq / all possible numbers i.e. 11238513
|
# every ticket has the same odds, the forecast just goes with the numbers that get called the most
|
||||||
Winning_Numbers = str("-".join(sorted_nums))
|
Chance = frac(1, comb(70, 5) * 24)
|
||||||
|
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}")
|
f"With percent chance of winning being {Chance}")
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
pandas==1.3.5
|
pandas==1.3.5
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
|
openpyxl
|
||||||
|
|||||||
@@ -4,15 +4,17 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
# Edit to your need
|
# Edit to your need
|
||||||
|
|
||||||
echo "Powerball" &&
|
echo "<--------> Powerball <-------->" &&
|
||||||
python lottopy_pb.py &&
|
python lottopy_pb.py &&
|
||||||
echo "MegaMillions" &&
|
echo "<--------> MegaMillions <-------->" &&
|
||||||
python megamil.py &&
|
python megamil.py &&
|
||||||
echo "Lotto America" &&
|
echo "<--------> Lotto America <-------->" &&
|
||||||
python lotto_america.py &&
|
python lotto_america.py &&
|
||||||
echo "Daily3" &&
|
echo "<--------> Daily3 <-------->" &&
|
||||||
python daily3.py &&
|
python daily3.py &&
|
||||||
echo "Daily4" &&
|
echo "<--------> Daily4 <-------->" &&
|
||||||
python daily4.py &&
|
python daily4.py &&
|
||||||
echo "Cash25" &&
|
echo "<--------> Cash25 <-------->" &&
|
||||||
python cash25.py
|
python cash25.py &&
|
||||||
|
echo "<--------> Cash Pop <-------->" &&
|
||||||
|
python cashpop.py
|
||||||
|
|||||||
Reference in New Issue
Block a user