Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancements to geohash-btc #2

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
83fbdab
Added parser to retrieve the latitude & longitude from the command line.
mibe Jul 29, 2011
79bb5cd
Added ability to use other markets than Mt. Gox.
mibe Jul 29, 2011
c683590
Consistent capitalization of help message.
mibe Jul 29, 2011
47f22d1
Use different mapping services for the map URL
mibe Jul 29, 2011
4ebc5a2
Fill latitude / longitude variables with geohash position
mibe Jul 29, 2011
c679beb
Display map service provider in help message.
mibe Jul 29, 2011
d6c0613
List available symbols at bitcoincharts
mibe Jul 30, 2011
33b6650
Bitcoin Charts switched to rolling intervals, so there is no opening …
mibe May 20, 2012
e3e05d0
Merge branch 'bcc-fix'
mibe May 20, 2012
0f4d477
Display error message if BCC has no price data for a given market
mibe May 20, 2012
fce810a
Implemented 30W Time Zone Rule
mibe May 20, 2012
8e776de
Use subparsers for argument parsing.
mibe May 26, 2012
715bfcb
Defined functions for every code part.
mibe May 27, 2012
4b2fa33
Implemented support for calculation the globalhash.
mibe May 27, 2012
10140a1
Error checking on latitude & longitude input.
mibe May 27, 2012
3721e73
List available symbols at bitcoincharts. The code got somehow lost wh…
mibe May 27, 2012
5b27910
Print latest market trade time also.
mibe May 27, 2012
cc72e08
URL of Bitcoincharts.com API updated
mibe Feb 28, 2015
6a53c22
Fixed mapping service URLs.
mibe Feb 28, 2015
a028b78
Using SSL on all URLs, except for OSM.
mibe Feb 28, 2015
0d57766
Using coinbaseUSD as default symbol.
mibe Nov 5, 2016
4049841
Update for Python 3 compatibility (tested with Python 3.8.2).
mibe Apr 11, 2020
343ac96
Using different symbol, since the old one returned old data only.
mibe Apr 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 171 additions & 62 deletions geohash.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,171 @@
#!/usr/bin/python

# Copyright 2011 Mark Holmquist
# This script is free software, licensed under the GPLv3, of which you should have received a copy with this software.
# If you didn't, I apologize, but you'll be able to find it at /usr/share/common-licences/GPL-3 or http://www.gnu.org/licenses/gpl-3.0.txt

# This script will calculate a geohash location for you based on the opening price at Mt. Gox for BTC/USD trades.
# Usually, people use the DJIA for this algorithm, but I didn't think that was nerdy enough :)
# It will also automagically give you a link to a google map to the location.
# If you'd like any help with it, don't hesitate to open up an issue at github.
# Have fun!

import datetime
import hashlib
import json
import urllib

latitude = 33
longitude = -116

btcinfo = urllib.urlopen("http://bitcoincharts.com/t/markets.json")
jsoninfo = btcinfo.read()

dictinfo = json.loads(jsoninfo)

todayopen = -1
for sym in dictinfo:
if sym["symbol"] == "mtgoxUSD":
todayopen = sym["open"]
else:
continue

if todayopen < 0:
raise ValueError("No data from bitcoincharts, is it down?")

thestring = str(datetime.date.today()) + "-" + str(todayopen)

thehash = hashlib.md5(thestring).hexdigest()

hexnum = (thehash[0:16], thehash[16:32])

curpow = 1
decnum = [0.0, 0.0]

while curpow <= len(hexnum[0]):
decnum[0] += int(hexnum[0][curpow-1], 16) * (1.0 / (16.0 ** curpow))
decnum[1] += int(hexnum[1][curpow-1], 16) * (1.0 / (16.0 ** curpow))
curpow += 1

if latitude >= 0:
decnum[0] += latitude
else:
decnum[0] -= latitude
decnum[0] *= -1

if longitude >= 0:
decnum[1] += longitude
else:
decnum[1] -= longitude
decnum[1] *= -1

print "http://maps.google.com/maps?q=" + str(decnum[0]) + "," + str(decnum[1]) + "(Geohash+for+" + str(datetime.date.today()) + ")&iwloc=A"
#!/usr/bin/python

# Copyright (C) 2011 Mark Holmquist
# Copyright (C) 2011, 2012, 2015, 2016, 2020 Michael Bemmerl

# This script is free software, licensed under the GPLv3, of which you should have received a copy with this software.
# If you didn't, I apologize, but you'll be able to find it at /usr/share/common-licences/GPL-3 or http://www.gnu.org/licenses/gpl-3.0.txt

# This script will calculate a geohash location for you based on the first price at a market for BTC trades after midnight (UTC).
# Usually, people use the DJIA for this algorithm, but I didn't think that was nerdy enough :)
# It will also automagically give you a link to a google map to the location.
# If you'd like any help with it, don't hesitate to open up an issue at github.
# Have fun!

from datetime import date, datetime
import hashlib, urllib.request, urllib.parse, urllib.error, argparse, time, csv, json

parser = argparse.ArgumentParser(description="Calculate a geohash location based on the midnight price for BTC trades.")

subparsers = parser.add_subparsers(help="sub-commands", dest="parser")

globalhash_parser = subparsers.add_parser("globalhash", help="calculate the globalhash")
globalhash_parser.add_argument('-s', '--symbol', help="symbol of the market (default: krakenUSD)", default="krakenUSD")
globalhash_parser.add_argument('-m', '--map', help="print URL to a mapping service instead of displaying the raw latitude & longitude.", default="", choices=["google", "osm", "yahoo", "bing"])

graticule_parser = subparsers.add_parser("graticule", help="calculate the geohash of a graticule")
graticule_parser.add_argument('lat', help="latitude (integer part)", type=int)
graticule_parser.add_argument('lon', help="longitude (integer part)", type=int)
graticule_parser.add_argument('-s', '--symbol', help="symbol of the market (default: krakenUSD)", default="krakenUSD")
graticule_parser.add_argument('-m', '--map', help="print URL to a mapping service instead of displaying the raw latitude & longitude.", default="", choices=["google", "osm", "yahoo", "bing"])

list_symbols_parser = subparsers.add_parser("list-symbols", help="list all available symbols")

def get_midnight(thirtyw_rule):
"""Calculate unix timestamp of last midnight (UTC)"""
utc_unix = time.time()
midnight = utc_unix - utc_unix % 86400

if thirtyw_rule:
midnight -= 86400

return midnight

def get_price(timestamp, symbol):
"""Returns the first price after the unix date in timestamp"""
try:
csvinfo = urllib.request.urlopen("https://api.bitcoincharts.com/v1/trades.csv?symbol={0}&start={1}".format(symbol, int(timestamp)))
except IOError as e:
(errno, strerror) = e.args
print("Could not retrieve data from bitcoincharts: " + str(strerror))
raise SystemExit

firstline = csvinfo.read().decode().splitlines()[0]
reader = csv.reader([firstline], delimiter=',')

firstprice = -1

try:
firstprice = next(reader)[1] # Price is in the second column
except StopIteration:
raise ValueError("No price data for symbol \"{0}\".".format(symbol))
except IndexError:
raise ValueError("Symbol \"{0}\" not found. Try another one.".format(symbol))

return firstprice

def algorithm(date, price):
"""Calculate the geohash algorithm and return a tupel with the results for latitude & longitude"""
thestring = str(date) + "-" + str(price)

thehash = hashlib.md5(thestring.encode('utf-8')).hexdigest()

hexnum = (thehash[0:16], thehash[16:32])

curpow = 1
decnum = [0.0, 0.0]

while curpow <= len(hexnum[0]):
decnum[0] += int(hexnum[0][curpow-1], 16) * (1.0 / (16.0 ** curpow))
decnum[1] += int(hexnum[1][curpow-1], 16) * (1.0 / (16.0 ** curpow))
curpow += 1

return decnum

def graticule(decnum, latitude, longitude):
"""Calculate the geohash coordinates for a graticule."""
if latitude >= 0:
latitude += decnum[0]
else:
latitude += decnum[0] * -1

if longitude >= 0:
longitude += decnum[1]
else:
longitude += decnum[1] * -1

return (latitude, longitude)

def globalhash(decnum):
"""Calculate the globalhash coordinates."""
latitude = decnum[0] * 180 - 90
longitude = decnum[1] * 360 - 180

return (latitude, longitude)

def print_coords(map, latitude, longitude):
"""Print the coordinates on the console."""
url = ""

if map == "google":
url = "https://maps.google.com/maps?q={0},{1}({2})&iwloc=A"
elif map == "osm":
url = "http://osm.org/?mlat={0}&mlon={1}#map=14/{0}/{1}"
elif map == "yahoo":
url = "https://maps.yahoo.com/map/?lat={0}&lon={1}&bb={2},{3},{4},{5}"
elif map == "bing":
url = "https://www.bing.com/maps/?v=2&cp={0}~{1}&lvl=14&dir=0&sp=point.{0}_{1}_{2}"

if map != "":
if map == "yahoo":
print(url.format(latitude, longitude, latitude + 0.01, longitude + 0.01, latitude - 0.01, longitude - 0.01))
else:
print(url.format(latitude, longitude, "Geohash+for+" + str(date.today())))
else:
print("latitude: " + str(latitude))
print("longitude: " + str(longitude))

def list_symbols():
jsoninfo = ""

try:
btcinfo = urllib.request.urlopen("https://api.bitcoincharts.com/v1/markets.json")
jsoninfo = btcinfo.read()
jsoninfo = json.loads(jsoninfo)
except IOError as e:
(errno, strerror) = e.args
print("Could not retrieve data from bitcoincharts: " + str(strerror))
raise SystemExit

print("symbol name".ljust(20) + "last trade")
for sym in jsoninfo:
print(sym["symbol"].ljust(20) + str(datetime.fromtimestamp(int(sym["latest_trade"]))))

#
# End of function definitions
#

args = parser.parse_args()

if args.parser == "graticule":
if abs(args.lat) > 90 or abs(args.lon) > 180:
raise ValueError("Graticule coordinates out of range.")

# 30W Time Zone Rule (see http://wiki.xkcd.com/geohashing/30W)
midnight = get_midnight(args.lat > -30)

price = get_price(midnight, args.symbol)
decnum = algorithm(date.today(), price)

coords = graticule(decnum, args.lat, args.lon)
print_coords(args.map.lower(), coords[0], coords[1])
elif args.parser == "globalhash":
midnight = get_midnight(True) # Globalhash is always with 30W rule.

price = get_price(midnight, args.symbol)
decnum = algorithm(date.today(), price)

coords = globalhash(decnum)
print_coords(args.map.lower(), coords[0], coords[1])
elif args.parser == "list-symbols":
list_symbols()