ХФ17 get_accounts python
Сначала ты веришь в Деда Мороза, потом не веришь... а потом ты сам Дед Мороз. Так и с библиотеками питона для взаимодействия с голосом. После ХФ работоспособным пока является вариант от @vvk golos-piston и сегодня мы поговорим о том, как начинать писать свои api для более лучшей работы скриптов/ботов на питоне.
Очень неудобный модуль в оригинальном пистоне - это модуль Account, который предполагает работу с одним аккаунтом. Так что когда у тебя студботнет на 66 персон и ты хочешь понять кем можно апнуть, так как батарейка не просела, а кем не стоит... этот класс уже не есть лучшее решение. Поэтому напишем свою функцию, которая будет одновременно получать информацию по необходимым аккаунтам в удобоваримом виде.
from piston import Steem
from datetime import datetime
golos = Steem(node = 'wss://ws17.golos.io')
logins = ['ksantoprotein', 'sci-populi', 'vp-cosmos']
accounts = get_accounts(logins)
Вот такая предварительная магия питона. Мы задаем список логинов и вызываем нашу функцию get_accounts и получаем список словарей с необходимой информацией. Если же нас будет интересовать только один пользователь (а так и реализовано в оригинальном пистоне), то вызов будет такой.
login = 'ksantoprotein'
account = get_accounts([login])
Мы просто строковую переменную login запихаем при вызове сразу в список.
А теперь опишем нашу авторскую функцию get_accounts
def get_accounts(logins):
accounts = golos.rpc.get_accounts(logins, api='database_api')
info_golos = golos.rpc.get_dynamic_global_properties(api='database_api')
feed = golos.rpc.get_feed_history(api='database_api')
base = float(feed["current_median_history"]["base"].split()[0])
quote = float(feed["current_median_history"]["quote"].split()[0])
median_price = round(base / quote, 3)
# Obtain STEEM/VESTS ratio
total_vesting_fund_steem = float(str(info_golos["total_vesting_fund_steem"]).split()[0])
total_vesting_shares = float(str(info_golos["total_vesting_shares"]).split()[0])
total_reward_fund_steem = float(str(info_golos["total_reward_fund_steem"]).split()[0])
total_reward_shares2 = int(info_golos["total_reward_shares2"])
golos_per_vests = total_vesting_fund_steem / total_vesting_shares
NOW = datetime.strptime(info_golos["time"], "%Y-%m-%dT%H:%M:%S")
Мы тут аж три раза обратимся к блокчейну. Сначала получим оригинальную информацию по аккаунтам в accounts и так как мы хотим посчитать таки реальную батарейку, то еще загрузим текущие динамические переменные и для довеска рассчитаем так называемую медиану, он же курс фидо или курс делегатов.
Так же нам понадобится golos_per_vests - это поможет рассчитать силу голоса аккаунта, и обязательно фиксируем текущее время блокчейна в переменной NOW без чего нам не высчитать реальное значение батарейки... ооооууууооо... простите, не сдержался и подпел.
Теперь мы готовы пройтись циклом по полученному списку и внести необходимые изменения
for account in accounts:
# Определение ликвидных токенов
account["GOLOS"] = float(str(account["balance"]).split()[0])
account["GBG"] = float(str(account["sbd_balance"]).split()[0])
Меня реально сильно раздражает, что формат наших токенов представляется в формате amount, поэтому сразу отделяю числовое значение и уже далее буду оперировать типом переменной float, а так как account - это словарь, то можно с легкость добавить необходимые ключи GBG и GOLOS. Так что в дальнейшем скрипту будет проще оперировать, а главное понятнее для стороннего чтения питоновского текста.
# Определение реальной батарейки 1-10000
VP = float(account["voting_power"])
last_vote_time = datetime.strptime(account["last_vote_time"], "%Y-%m-%dT%H:%M:%S")
age = (NOW - last_vote_time).total_seconds() / 1
actualVP = VP + (10000 * age / 432000)
if actualVP > 10000:
account["voting_power"] = 10000
else:
account["voting_power"] = round(actualVP)
А таким образом считается реальная батарейка. Используя время последнего апвота и отсчитав сколько прошло до текущего момента по некой формуле считается реальный процент. Единственно я оставляю значение в формате int (от 1 до 10000), а не float (от 0.01 до 100.00%). Поверьте, так лучше. И если прошло более суток, то батарейка считается равной 100% в своей зарядке!
# Определение golos_power (SP)
vests = float(str(account["vesting_shares"]).split()[0])
account["golos_power"] = round(vests * golos_per_vests, 3)
В блокчейне наша сила голоса хранится в GEST или VEST. Я давно перестал пытаться вникнуть чем размерность одного отличается от другого (все-таки пистон наследовал стимит больше). Посему предпочитаю порядок цифр контролировать самостоятельно и заодно вписать в словарь новый ключ golos_power.
И раз Остапа понесло, то при переходе на линейку можно вычислить сколько же принесет ваш апвот куда-либо.
# Определение rshares
vesting_shares = int(1e6 * account["golos_power"] / golos_per_vests)
max_vote_denom = info_golos["vote_regeneration_per_day"] * (5 * 60 * 60 * 24) / (60 * 60 * 24)
used_power = int((account["voting_power"] + max_vote_denom - 1) / max_vote_denom)
rshares = ((vesting_shares * used_power) / 10000)
account["rshares"] = round(rshares)
# Определение стоимости апвота
value_golos = round(account["rshares"] * total_reward_fund_steem / total_reward_shares2, 3)
value_gbg = round(value_golos * median_price, 3)
account["value"] = {"GOLOS": value_golos, "GBG": value_gbg}
Так как покерное прошлое дает немного о себе знать, поэтому запихал полученные значения с учетом медианного курса в ключ value (валью бет, шоу даун вэлью)... "ценность"... прогнозируемая на текущий момент ценность вашего апвота (без учета кураторских само собой).
Осталось только вернуть обновленный список
return(accounts)
И пользоваться. Мне приглянулся такой подход, теперь данную функцию можно описать в виде класса, подключать к своим ботам и спокойно оперировать полученным в "один" проход. При этом если снова сменят линейку, то можно переписать код в одном месте или добавить что-то еще дополнительно. К примеру я так и не разобрался с бандвишем и формулами @vvk и пока еще не додумал как бы можно было бы их внедрить в эту функцию, чтобы потом можно было бы прогнозировать, а сможет ли тот или иной аккаунт совершить то или иное действие.
Меня радует, что в чатах появляется народ, кто осваивает питон для доступа к блокчейну, поэтому есть для кого постить подобную информацию. Если что здесь инструкция по установке golos-piston в связке с python 3.5.