Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python script to calculate time to win full block and revenue per day. (GPU MINING)
#!/usr/bin/python
# -*- coding: utf-8 -*-
# "Whattomine GPU Hash time calculator"
#
# This is not for CPU or ASIC calculations.
# Author: Brady Shea
# Email: Use github user: bmatthewshea or gist comments
# Origin: https://gist.github.com/bmatthewshea/90b120722e0561dd235adcdc231b6765
#
# If this script helps you, please consider a small donation!
#
# BTC 1CmuTLFoApWRxXRaZvpsQ1cC9gdJSef3K6
# ETH 4e06e4080E6043dfF23c8b634712Aca2e1DE4347
# LTC LawZKPgkUc1DJRjdMqH2u8L6cgSMpD8H2E
# XMR 49mRDhPU1qURWT5g9ZPuexELwSr1VUpKMQMPRHTkkezXG3eQ1rHYedkieb7RkzPkVrW9QPm3r6cLA1AuJEDKLrqzRFPyZ79
# XVG/Verge D64XkTk9YnR2HX3CupZWxWnWwC3TVDRt3T
# FTC/FeatherCoin 6sStepeFZg3o4VYb2HRNJmw2sRnfVJhmdQ
# Thank you!
# Currently the script calculates on many coin types/algos but is more accurate on ethash:
# (ETH, ETC, EXP, PIRL, UBIQ, ELLA, MUSIC, SOIL, etc) neoscript, lyra, cryptonight/note should also be accurate
# THIS IS A WORK IN PROGRESS - EXCUSE THE MESS.
# Non-GPU minable asic algos (SHA-256 + any others) hashtimes are displayed as if using a GPU (In TH).
# In other words, they are shown just for fun.
import json, requests, collections, math, argparse, sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# You can adjust this however you want:
minerapi = 'https://whattomine.com/calculators.json'
priceapi = 'https://api.coindesk.com/v1/bpi/currentprice.json'
speeds = ['10.0', '15.0', '20.0', '25.0', '30.0', '50.0', '100.0', '250.0', '300.0', '350.0', '600.0', '650.0', '750.0', '1000.0', '2000.0', '3000.0', '4000.0', '5000.0', '10000.0']
heading0 = "Note: Ethash, equihash, neoscript, cryptonight and lyra calculations are more precise than others.\n The times below are 'averages'. Seconds are at 1.0/100% variance to win a full block."
heading1 = "Speed Secs to win block Time to win block Coins/Day - USD Revenue"
heading2 = "========== ======================== ======================== ======================="
# Dictionary for modifiers on hash calculation and text labels for hash speed
dModifiers = {}
# Lower means longer times
dModifiers ={
'SHA-256': {'modifier': 0.98e12, 'dHlabel': "TH" }, \
'Skunkhash': {'modifier': 616666.0, 'dHlabel': "MH" }, \
'Pascal': {'modifier': 22999977.0, 'dHlabel': "MH" }, \
'LBRY': {'modifier': 4499995.0, 'dHlabel': "MH" }, \
'Groestl': {'modifier': 616666.0, 'dHlabel': "MH" }, \
'X11Gost': {'modifier': 229999.7, 'dHlabel': "MH" }, \
'Blake2b': {'modifier': 32999967.0, 'dHlabel': "MH" }, \
'Blake14r': {'modifier': 44999955.0, 'dHlabel': "MH" }, \
'NeoScrypt': {'modifier': 1192.0, 'dHlabel': "KH" }, \
'Lyra2REv2': {'modifier': 1e6, 'dHlabel': "MH" }, \
'Equihash': {'modifier': 0.000235, 'dHlabel': "H" }, \
'TimeTravel10': {'modifier': 1e6, 'dHlabel': "MH" }, \
'Xevan': {'modifier': 1e3, 'dHlabel': "KH" }, \
'CryptoNight': {'modifier': 1, 'dHlabel': "H" }, \
'CryptoNightV7': {'modifier': 1, 'dHlabel': "H" }, \
'Ethash': {'modifier': 1e6, 'dHlabel': "MH" }, \
'Etchash': {'modifier': 1e6, 'dHlabel': "MH" }, \
'Autolykos': {'modifier': 1e6, 'dHlabel': "MH" }, \
'Ubqhash': {'modifier': 1e6, 'dHlabel': "MH" }
}
# So far: ETHASH, CNIGHT, NEOSCRIPT, LYRA2, TimeTravel should be precise/done
# Add some flags for command line and parse
parser = argparse.ArgumentParser(description='Grab crypto-coin data and do block time calculations.')
parser.add_argument('-m', '--manual', action='store_true', help='Enter current blocktime and nethash rate manually')
parser.add_argument('-n', '--name', help='Crypto-coin full name. Example: Ethereum')
parser.add_argument('-s', '--symbol', help='Crypto-coin symbol name. Example: ETH')
args = parser.parse_args()
# label,seconds conversions
intervals = (
('years', 31557600), # 60 * 60 * 24 * 7 * 52.143.... <- using astronomical secs in year
('weeks', 604800), # 60 * 60 * 24 * 7
('days', 86400), # 60 * 60 * 24
('hours', 3600), # 60 * 60
('minutes', 60),
('seconds', 1),
)
#console colorcode
SETRED = '\033[31m'
SETLRED = '\033[91m'
SETGREEN = '\033[32m'
SETLGREEN = '\033[92m'
SETYELLOW = '\033[33m'
SETLYELLOW = '\033[93m'
SETBLUE = '\033[34m'
SETLBLUE = '\033[94m'
SETMAGENTA = '\033[35m'
SETLMAGENTA = '\033[95m'
SETCYAN = '\033[36m'
SETLCYAN = '\033[96m'
SETGREY = '\033[37m'
SETLGREY = '\033[97m'
RESET_COLOR = '\033[0m'
# DEFs
def setcolor(colorcodestr, str):
color_line = colorcodestr + str + RESET_COLOR
return color_line
#print (SETBLUE, "Test color.")
# (default time granularity =2 fields) - https://stackoverflow.com/a/24542445/503621
def display_time(seconds, granularity=2):
result = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ', '.join(result[:granularity])
# Create a keypaths for reverse dictionary call
def keypaths(nested):
for key, value in nested.items():
if isinstance(value, collections.abc.Mapping):
for subkey, subvalue in keypaths(value):
yield [key] + subkey, subvalue
else:
yield [key], value
def printTimeTable(speed, label, hashtime, coinsperday, revenue):
print("{0:<7}{1:>1} {2:>25} {3:>25} {4:8.8f} - ${5:.2f}".format(speed, " " + label, str(int(hashtime)) + " seconds", display_time(int(hashtime)), coinsperday, revenue))
return
def setlabelmodifier(labelarg): #manual entry label/modifier
if labelarg == "K":
imod=1000
if labelarg == "M":
imod=1e6
if labelarg == "G":
imod=1e9
if labelarg == "T":
imod=1e12
if labelarg == "H":
imod=1
else: # append H on others
labelarg += "H"
return labelarg, imod
def getuserspeed(): # ask for if user wants table output or specific speed?
while True:
try:
userspeed = float(input(" Please enter a mining speed to calculate or <Enter> for default table speeds (30.0 = 30MH): "))
except (ValueError, NameError, SyntaxError):
userspeed = 0.0 # figure it's non-float/int or <enter>
eraseline() # just remove line since it's ignored anyway
break
else: # needs some validation - assume it's valid int - break and return it:
print
break
return userspeed
def eraseline():
CURSOR_UP_ONE = '\x1b[1A'
ERASE_LINE = '\x1b[2K'
print(CURSOR_UP_ONE + ERASE_LINE)
# MANUAL LOOKUP
if args.manual:
print("Manual entry:\nNote that calculating using difficulty isn't very accurate, but you need less input.\nWorks best on ETHash type coins and not at all on others.\n")
sCalctype = ""
while not sCalctype or sCalctype not in ('d', 'n'):
sCalctype = str(raw_input(" Calculate using (d)ifficulty or (n)etwork hashrate: "))
if sCalctype == "d":
while True:
try:
iDifficulty = int(input(" Enter Difficulty (Example: 3242258038793980): "))
except (ValueError, NameError):
print("Not a number. Try again.")
continue
else:
break
if iDifficulty <= 10000:
print("The difficulty entered is too low to calculate.")
sys.exit()
# ask if user wants table output or specific speed? (enter does table)
fOutputspeed = 0.0
fOutputspeed = getuserspeed()
sHashlabel = ""
while not sHashlabel or sHashlabel not in ('h', 'k', 'm', 'g', 't'):
sHashlabel = str(raw_input(" Enter output speed ('h' = Hashes', 'k' = KH, 'm' = MH, 'g' = GH, 't' = TH): "))
sHashlabel = sHashlabel.upper()
sHashlabel, iMultiplier = setlabelmodifier(sHashlabel)
print
print(heading1 + "\n" + heading2)
for currentspeed in speeds:
iMySpeed = int(float(currentspeed)) * iMultiplier
fHashtime = iDifficulty / iMySpeed
printTimeTable(currentspeed, sHashlabel, fHashtime, 0.0000, 0.00)
print
sys.exit()
#not difficulty? do nethashrate , block time
while True:
try:
iNethash = int(input(" Enter Network Hashrate (Example: 225534691668477): "))
except (ValueError, NameError):
print("Not a number. Try again.")
continue
else:
break
if iNethash <= 10000:
print("The hashrate entered is too low to calculate.")
sys.exit()
while True:
try:
fBlocktime = float(input(" Enter current Blocktime (Example: '15.0'): "))
except (ValueError, NameError):
print("Not a number and/or decimal. Try again.")
continue
else:
break
while True:
try:
fBlockreward = float(input(" Enter block reward or <Enter> for None (Example: '5.0'): "))
except (ValueError, NameError):
fBlockreward = "n/a"
continue
else:
break
# ask if user wants table output or specific speed? (enter does table)
fOutputspeed = 0.0
fOutputspeed = getuserspeed()
# ask user for type of output label/multiplier
sHashlabel = ""
while not sHashlabel or sHashlabel not in ('h', 'k', 'm', 'g', 't'):
sHashlabel = str(raw_input(" Enter output speed ('h' = Hashes', 'k' = KH, 'm' = MH, 'g' = GH, 't' = TH): "))
sHashlabel = sHashlabel.upper()
sHashlabel, iMultiplier = setlabelmodifier(sHashlabel)
print
print(heading1 + "\n" + heading2)
unitsperday = 0.00
for currentspeed in speeds:
iMySpeed = int(float(currentspeed)) * iMultiplier
fHashtime = iNethash / iMySpeed * fBlocktime
idifficulty = fHashtime * iMySpeed
if (fBlockreward != "n/a" or fBlockreward != ""):
unitsperday = (( iMySpeed * fBlockreward) / idifficulty) * 3600 * 24
else:
unitsperday = fBlockreward
if fHashtime < fBlocktime:
fHashtime = fBlocktime * 1.1
printTimeTable(currentspeed, sHashlabel, fHashtime, unitsperday, 0.00)
print
sys.exit()
# Nothing on command line?:
if not (args.symbol or args.name):
print("Nothing to do. Try \'-h\' - exiting.")
sys.exit()
# Lookup symbol if used and update var coinName
if args.symbol:
sSymbol = args.symbol.upper()
url = minerapi
resp = requests.get(url)
fulldata = json.loads(resp.text)
reverse_dict = {}
for keypath, value in keypaths(fulldata):
reverse_dict.setdefault(value, []).append(keypath)
CoinKeysLookup = reverse_dict[sSymbol]
# set coin name to use it for NAME LOOKUP below
coinName = CoinKeysLookup[0][1]
# NAME LOOKUP -> LOOK FOR COIN BY FULL NAME (use -n/--name)
try:
coinName # chk if defined by the symbol look already? ^
except NameError: # if it isn't set the lookup to name from command line:
coinName = args.name # we already verified args.name exists above or wld have exited
# fulldata didnt populate since its a name not symbol
url = minerapi
resp = requests.get(url)
fulldata = json.loads(resp.text)
# Give user some info if found or exit.
for items in fulldata['coins']:
if items == coinName:
coin_id = fulldata['coins'][coinName]['id']
coin_symbol = fulldata['coins'][coinName]['tag']
print("%s" % setcolor(SETGREEN, "\n" + coinName + "(" + coin_symbol + ") has been found at \'whattomine.com\' with ID " + str(coin_id) + ".\n"))
url2 = 'https://whattomine.com/coins/' + str(coin_id) + '.json'
resp2 = requests.get(url2)
coindata = json.loads(resp2.text)
if 'errors' in coindata:
print("Sorry: The coin was found, but WhatToMine reports an error on that ID's JSON request.\n")
print("Try consulting the json request here: \n" + url2 + "\n")
sys.exit()
break
else:
print("\nSorry: Either your coin wasn't found or whattomine is down.\n")
sys.exit()
#sys.exit()
# Grab some prices for conversions
btc_prices = priceapi
#turned off verify - coindesk api ssl broken (11/2018)
r = requests.get(btc_prices, verify=False)
pricedata = json.loads(r.text)
USD = pricedata["bpi"]["USD"]["rate"].replace(',','')
GBP = pricedata["bpi"]["GBP"]["rate"].replace(',','')
EUR = pricedata["bpi"]["EUR"]["rate"].replace(',','')
BTCToUSD = float(USD)
BTCToGBP = float(GBP)
BTCToEUR = float(EUR)
# Grab rate/set currencies
fPrice = coindata.get('exchange_rate', "Not found.")
if not coinName == "Bitcoin":
fUSDrate = fPrice * BTCToUSD
fGBPrate = fPrice * BTCToGBP
fEURrate = fPrice * BTCToEUR
else:
fUSDrate = BTCToUSD
fGBPrate = BTCToGBP
fEURrate = BTCToEUR
fPrice = 1.00
sDifficulty = coindata.get('difficulty', "Not found.")
fDifficulty = float(sDifficulty)
sCurrentblock = coindata.get('last_block', "Not found.")
sBlockreward = coindata.get('block_reward', "Not found.")
fBlockreward = float(sBlockreward)
sBlocktime = coindata.get('block_time', "Not found.")
fBlocktime = float(sBlocktime)
sNethash = coindata.get('nethash', "Not found.")
iNethash = int(str(sNethash))
sAlgo = coindata.get('algorithm', "Not found.")
fModifier = dModifiers[sAlgo]['modifier']
sHashlabel = dModifiers[sAlgo]['dHlabel']
# Print results
print("Coin: %s" % setcolor(SETYELLOW, coinName))
print( "Symbol/Tag: %s" % setcolor(SETYELLOW, coin_symbol))
print
print("Algorithm: %s" % sAlgo)
print("Difficulty: %.2f" % fDifficulty)
print("Current Block: %s" % sCurrentblock)
print("Block Reward: %s" % sBlockreward)
print("Blocktime: %s" % sBlocktime)
print("Current Nethash: %s" % sNethash)
print
print("Exchange rate (BTC): %f" % fPrice)
print( "USD, GBP, EUR: ${:<12.4f} £{:<12.4f} €{:<12.2f}".format(fUSDrate, fGBPrate, fEURrate))
if coinName == "Bitcoin":
print("Block Profit(1 block): ${:<12.2f} £{:<12.2f} €{:<12.2f}".format(BTCToUSD * fBlockreward, BTCToGBP * fBlockreward, BTCToEUR * fBlockreward))
else:
print("Block Profit(1 block): ${:<12.2f} £{:<12.2f} €{:<12.2f}".format(fUSDrate * fBlockreward, fGBPrate * fBlockreward, fEURrate * fBlockreward))
print
print(heading0)
print
# ask if user wants table output or specific speed? (enter does table)
fOutputspeed = getuserspeed()
print(heading1 + "\n" + heading2)
#lyra using target modifier
#target = 32
target = 32.8
multiplier = 1
# 24 * 60 * 60 :
secsinday=86400
if fOutputspeed != 0.0:
fSpeed = fOutputspeed * fModifier
wtmhashtime = round(iNethash / fSpeed * fBlocktime)
print(wtmhashtime)
print(round(wtmhashtime))
print(fBlocktime)
if wtmhashtime <= fBlocktime:
wtmhashtime = int(fBlocktime + 1.0)
coinsperday = (secsinday * fBlockreward) / wtmhashtime
usd_coins = fUSDrate * coinsperday
printTimeTable(fOutputspeed, sHashlabel, wtmhashtime, coinsperday, usd_coins)
print
else:
for currentspeed in speeds:
fSpeed = float(currentspeed) * fModifier
wtmhashtime = iNethash / fSpeed * fBlocktime
# #generic/ethash/all others
# unitsperday = (fBlockreward * (secsinday / fBlocktime) * (float(currentspeed) * 1000000) / iNethash) * multiplier
# if sAlgo == "Lyra2REv2":
# unitsperday = (fBlockreward / (fDifficulty * math.pow(2, target) / (float(currentspeed) * 1000000) / 3600 / 24)) * multiplier
# if sAlgo == "CryptoNightV7" or sAlgo == "CryptoNight":
# unitsperday = (fBlockreward * (secsinday / fBlocktime)) * (float(currentspeed) * 1000000) / (fDifficulty / 60) * multiplier
# ^ I have left calcs above in code (for now) for 'unitsperday' which are accurate - Instead we use the data available already from W2M and previously calculated speed/hashrate/seconds:
coinsperday = (secsinday * fBlockreward) / wtmhashtime
usd_coins = fUSDrate * coinsperday
printTimeTable(currentspeed, sHashlabel, wtmhashtime, coinsperday, usd_coins)
print
@bmatthewshea
Copy link
Author

bmatthewshea commented Dec 22, 2017

whattomine-hashtimes.py -h - Help
whattomine-hashtimes.py -s ETH - Use Symbol lookup
whattomine-hashtimes.py -n Ethereum - Use Name lookup
whattomine-hashtimes.py -m - Manual entry (use nethash or difficulty for input). ethash coins work best if using difficulty calc.

@bmatthewshea
Copy link
Author

bmatthewshea commented Apr 7, 2018

  • Added timetravel and xevan algos
  • Added coins per day / revenue per day in USD

whattomine-python-timetravel-added-2018-04-07_085610

@argesdaniel
Copy link

argesdaniel commented May 15, 2021

Thks for the code.
I just downloaded and compiled. I'm using Python 3.8.5.
I'm getting a syntax error on line 99
display_time(int(hashtime)), coinsperday, revenue)
^
What can it be?

@bmatthewshea
Copy link
Author

bmatthewshea commented Jun 20, 2021

@argesdaniel

Thks for the code.
I just downloaded and compiled. I'm using Python 3.8.5.
I'm getting a syntax error on line 99
display_time(int(hashtime)), coinsperday, revenue)
^
What can it be?

Just saw this. Took a look last night.
Try now. Just fixed it for v3.8.5. One problem was the change in 'collections' > 'collections.abc' among other 3.8+changes.

@bmatthewshea
Copy link
Author

bmatthewshea commented Jun 20, 2021

Changes 20JUN2021

  • What2Mine and price api still working. Verified.
  • Updated to work with Python 3.8+. I still don't have much error trapping done. If you see an error let me know.
  • NOTE: Python 2.x will no longer work. I see no point keeping it cross compatible. If you still use Python 2 as 'python' default, install 3.8.x (Most Linux distros have it available) and set it as default Python binary, or edit first line in script to point at python3 binary.
  • Added some algos - havent fine tuned them yet- should be close to correct, though:
    Etchash (ETC/Ether Classic), Autolykos (ERG/Ergo), Ubqhash(Ubiq)

SHEA22-2021-06-20_102041

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment