Files
ProfitLib/ProfitLib.py
2015-07-08 09:52:19 -07:00

266 lines
9.9 KiB
Python
Executable File

#!/usr/bin/env python
# coding=iso-8859-1
# ProfitLib.py: mining profitability library
#
# Copyright © 2014-2015 Scott Alfter
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import jsonrpc
import sys
from decimal import *
from PyCryptsy import PyCryptsy
from bittrex import bittrex as Bittrex
from PyCCEX import PyCCEX
from PyCryptopia import PyCryptopia
from poloniex import poloniex
from bleuBot import bleuBot
class ProfitLib:
# store config dictionary, init output dictionary, and initialize PyCryptsy
def __init__(self, daemons, credentials):
self.daemons=daemons
self.out={}
self.api={}
for i, exch in enumerate(credentials):
if (exch=="cryptsy"):
self.api[exch]=PyCryptsy(str(credentials[exch]["pubkey"]), str(credentials[exch]["privkey"]))
elif (exch=="bittrex"):
self.api[exch]=Bittrex.Bittrex(str(credentials[exch]["pubkey"]), str(credentials[exch]["privkey"]))
elif (exch=="c-cex"):
self.api[exch]=PyCCEX(str(credentials[exch]["key"]))
elif (exch=="cryptopia"):
self.api[exch]=PyCryptopia()
elif (exch=="poloniex"):
self.api[exch]=poloniex(str(credentials[exch]["key"]), str(credentials[exch]["secret"]))
elif (exch=="bleutrade"):
self.api[exch]=bleuBot(str(credentials[exch]["key"]), str(credentials[exch]["secret"]))
else:
raise ValueError("unknown exchange")
# update market IDs
def GetMarketIDs(self):
self.mkts={}
for i, exch in enumerate(self.api):
if (exch=="cryptsy"):
try:
self.mkts[exch]={}
coins=self.api[exch].Query("getcoindata", {})["return"]
markets=self.api[exch].GetMarketIDs("BTC")
for j in coins:
if (j["code"].upper() in markets.keys() and j["maintenancemode"]=="0"):
self.mkts[exch][j["code"].upper()]=markets[j["code"].upper()]
except:
print "warning: Cryptsy offline"
elif (exch=="cryptopia"):
try:
self.mkts[exch]=self.api[exch].GetMarketIDs("BTC")
except:
print "warning: Cryptopia offline"
elif (exch=="bittrex"):
try:
self.mkts[exch]={}
m=self.api[exch].get_markets()["result"]
for j, market in enumerate(m):
if (market["BaseCurrency"].upper()=="BTC" and market["IsActive"]):
self.mkts[exch][market["MarketCurrency"].upper()]=market["MarketName"]
except:
print "warning: Bittrex offline"
elif (exch=="c-cex"):
try:
self.mkts[exch]={}
m=self.api[exch].Query("pairs", {})["pairs"]
for j, pair in enumerate(m):
if (pair.split("-")[1].upper()=="BTC"):
self.mkts[exch][pair.split("-")[0].upper()]=pair
except:
print "warning: C-CEX offline"
elif (exch=="poloniex"):
try:
self.mkts[exch]={}
m=self.api[exch].returnTicker()
for j, pair in enumerate(m):
if (pair.split("_")[0].upper()=="BTC" and m[pair]["isFrozen"]=="0"):
self.mkts[exch][pair.split("_")[1].upper()]=pair
except:
print "warning: Poloniex offline"
elif (exch=="bleutrade"):
try:
self.mkts[exch]={}
m=self.api[exch].getMarketSummaries()["result"]
for j, pair in enumerate(m):
if (pair["MarketName"].split("_")[1].upper()=="BTC" and pair["IsActive"]=="true"):
self.mkts[exch][pair["MarketName"].split("_")[0].upper()]=pair["MarketName"]
except:
print "warning: Bleutrade offline"
# get best bid from the exchanges
def GetBestBid(self, coin):
bids={}
for i, exch in enumerate(self.api):
if (exch=="cryptsy" or exch=="cryptopia"):
try:
bids[exch]=Decimal(self.api[exch].GetBuyPriceByID(self.mkts[exch][coin]))
except:
pass
elif (exch=="bittrex"):
try:
bids[exch]=Decimal(self.api[exch].get_ticker(self.mkts[exch][coin])["result"]["Bid"])
except:
pass
elif (exch=="c-cex"):
try:
bids[exch]=Decimal(self.api[exch].Query(self.mkts[exch][coin], {})["ticker"]["buy"])
except:
pass
elif (exch=="poloniex"):
try:
bids[exch]=Decimal(self.api[exch].returnOrderBook(self.mkts[exch][coin], 1)["bids"][0][0])
except:
pass
elif (exch=="bleutrade"):
try:
bids[exch]=Decimal(self.api[exch].getTicker(self.mkts[exch][coin])["result"][0]["bid"])
except:
pass
max_bid=(0, "none")
for i, exch in enumerate(bids):
if (Decimal(bids[exch])>Decimal(max_bid[0])):
max_bid=(bids[exch], exch)
return max_bid
# get latest profitability info
def Calculate(self):
self.GetMarketIDs()
for i, coin in enumerate(self.daemons):
if (self.daemons[coin]["active"]==1): # only check active configs
url="http://"+self.daemons[coin]["username"]+":"+self.daemons[coin]["passwd"]+"@"+self.daemons[coin]["host"]+":"+str(self.daemons[coin]["port"])
hashrate=Decimal(self.daemons[coin]["hashespersec"]) # our hashrate
self.out[coin]={}
# connect to coind
b=jsonrpc.ServiceProxy(url)
# get block reward, including transaction fees
# note #1: Novacoin (and coins derived from it?) report
# 1% of actual value here
# note #2: Namecoin doesn't support getblocktemplate, so get
# coinbase value from last block
# note #3: PPCoin doesn't want any parameters passed to
# getblocktemplate. Bitcoin requires at least
# an empty dictionary to be passed. Others don't
# care.
reward=Decimal(0)
try:
reward=Decimal(b.getblocktemplate()["coinbasevalue"])
except:
pass
if (reward==0):
try:
reward=Decimal(b.getblocktemplate({})["coinbasevalue"])
except:
pass
if (reward==0):
try:
vouts=b.decoderawtransaction(b.getrawtransaction(b.getblock(b.getblockhash(b.getblockcount()))["tx"][0]))["vout"]
for j, vout in enumerate(vouts):
reward+=vout["value"]
except:
pass
if (coin=="NVC" or coin=="DEM" or coin=="OSC" or coin=="PPC"):
reward*=100
# get proof-of-work difficulty
# try getmininginfo first to minimize RPC calls; only use
# getdifficulty if we must (as with NMC)
algo=self.daemons[coin]["algo"]
if (algo=="sha256"):
algo="sha256d"
try:
mining_info=b.getmininginfo()
diff=mining_info["difficulty_"+algo] # for MYR & other multi-algo coins
if (type(diff) is dict):
diff=diff["proof-of-work"]
except:
try:
diff=mining_info["difficulty"]
if (type(diff) is dict):
diff=diff["proof-of-work"]
except:
diff=b.getdifficulty()
if (type(diff) is dict):
diff=diff["proof-of-work"]
# get network hashrate
# note 1: Novacoin reports this in MH/s, not H/s
# note 2: Namecoin and Unobtanium don't report network hashrate, so
# return 0 (it's only informational anyway)
try:
nethashrate=mining_info["networkhashps"]
except:
try:
nethashrate=int(mining_info["netmhashps"]*1000000)
except:
nethashrate=0
# ported from my C# implementation at
# https://github.com/salfter/CoinProfitability/blob/master/CoinProfitabilityLibrary/Profitability.cs
interval=Decimal(86400) # 1 day
target=Decimal(((65535<<208)*100000000000)/(diff*100000000000))
revenue=Decimal(interval*target*hashrate*reward/(1<<256))
# write to output dictionary
self.out[coin]["reward"]=int(reward)
self.out[coin]["difficulty"]=float(Decimal(diff).quantize(Decimal("1.00000000")))
self.out[coin]["nethashespersec"]=int(nethashrate)
self.out[coin]["daily_revenue"]=int(revenue)
# if not Bitcoin, get exchange rate and BTC equivalent
if (coin!="BTC"):
bid=self.GetBestBid(coin.split("_")[0]) # 30 Jun 15: multi-algo compatibility
self.out[coin]["exchrate"]=float(Decimal(bid[0]).quantize(Decimal("1.00000000")))
self.out[coin]["exchange"]=bid[1]
self.out[coin]["daily_revenue_btc"]=int(Decimal(revenue*Decimal(bid[0])))
else:
self.out[coin]["exchrate"]=float(Decimal(100000000).quantize(Decimal("1.00000000")))
self.out[coin]["exchange"]="n/a"
self.out[coin]["daily_revenue_btc"]=int(revenue)
# copy these informational values from config dictionary
self.out[coin]["algo"]=self.daemons[coin]["algo"]
self.out[coin]["merged"]=self.daemons[coin]["merged"]
return self.out