coinbus-data/coinbus/btc_utxos_lyq2.py

1730 lines
78 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding=utf-8
import json
import os
import sys
import ujson
import time
import requests
from loguru import logger
from datetime import datetime, timedelta
from easybitcoinrpc import RPC
import csv
import sqlite3
from bitcoinutils.script import Script
from bitcoinutils.keys import P2wpkhAddress, P2wshAddress, P2shAddress, PrivateKey, PublicKey, SegwitAddress, P2pkhAddress
from bitcoinutils.setup import setup
import pymysql
import pymongo
from urllib import parse
import btc_historical_price
class UtxosIf:
def __init__(self):
self.balance_0 = 0
self.balance_001 = 0
self.balance_01 = 0
self.balance_1 = 0
self.balance_10 = 0
self.balance_100 = 0
self.balance_1000 = 0
self.balance_10000 = 0
self.balance_amount_0 = 0
self.balance_amount_001 = 0
self.balance_amount_01 = 0
self.balance_amount_1 = 0
self.balance_amount_10 = 0
self.balance_amount_100 = 0
self.balance_amount_1000 = 0
self.balance_amount_10000 = 0
self.profit_addresses = 0
self.loss_addresses = 0
self.profit_ratio = 0
self.lth_supply = 0
self.sth_supply = 0
self.realized_price = 0
self.relative_lth_sth = 0
self.lth_profit_supply = 0
self.lth_loss_supply = 0
self.lth_profit_ratio = 0
self.sth_profit_supply = 0
self.sth_loss_supply = 0
self.sth_profit_ratio = 0
self.slrv_ratio = 0
self.slrv_24h = 0
self.slrv_6m1y = 0
self.total_address = 0
self.miner_address = 0
self.miner_balance = 0
self.total_balance = 0
self.total_rcap = 0
self.holder_0 = 0
self.holder_1 = 0
self.holder_2 = 0
self.holder_3 = 0
self.holder_4 = 0
self.holder_5 = 0
self.holder_6 = 0
self.holder_7 = 0
self.holder_15 = 0
self.holder_30 = 0
self.holder_60 = 0
self.holder_90 = 0
self.holder_180 = 0
self.holder_360 = 0
self.holder_540 = 0
self.holder_720 = 0
self.holder_1080 = 0
self.holder_1440 = 0
self.holder_1800 = 0
self.holder_2160 = 0
self.holder_2520 = 0
self.holder_2880 = 0
self.holder_3240 = 0
self.holder_3600 = 0
self.holder_3960 = 0
self.holder_balance_0 = 0
self.holder_balance_1 = 0
self.holder_balance_2 = 0
self.holder_balance_3 = 0
self.holder_balance_4 = 0
self.holder_balance_5 = 0
self.holder_balance_6 = 0
self.holder_balance_7 = 0
self.holder_balance_15 = 0
self.holder_balance_30 = 0
self.holder_balance_60 = 0
self.holder_balance_90 = 0
self.holder_balance_180 = 0
self.holder_balance_360 = 0
self.holder_balance_540 = 0
self.holder_balance_720 = 0
self.holder_balance_1080 = 0
self.holder_balance_1440 = 0
self.holder_balance_1800 = 0
self.holder_balance_2160 = 0
self.holder_balance_2520 = 0
self.holder_balance_2880 = 0
self.holder_balance_3240 = 0
self.holder_balance_3600 = 0
self.holder_balance_3960 = 0
self.price_buy = {} # step 500
self.price_buy_amount = {} # step 500
self.diff_sell = {} # step 500
self.diff_sell_amount = {}
self.profit_sell = {} # step 5000
self.profit_sell_amount = {}
self.balance_0_days = {}
self.balance_001_days = {}
self.balance_01_days = {}
self.balance_1_days = {}
self.balance_10_days = {}
self.balance_100_days = {}
self.balance_1000_days = {}
self.balance_10000_days = {}
self.balance_amount_0_days = {}
self.balance_amount_001_days = {}
self.balance_amount_01_days = {}
self.balance_amount_1_days = {}
self.balance_amount_10_days = {}
self.balance_amount_100_days = {}
self.balance_amount_1000_days = {}
self.balance_amount_10000_days = {}
'''
self.current_dt = time.time()
self.current_dt2 = time.gmtime(int(self.current_dt))
self.current_daystr = time.strftime("%d %b %Y", self.current_dt2)
self.current_dayutc = int(time.mktime(time.strptime(self.current_daystr, "%d %b %Y")))
'''
self.mc = pymongo.MongoClient("mongodb://10.168.3.192:27018/")
self.mdb = self.mc["btcutxos2"]
# self.mdb.authenticate("root", "123456")
self.uprofit = 0
self.uloss = 0
self.lth_nupl = 0
self.sth_nupl = 0
self.lth_mv = 0
self.sth_mv = 0
self.lth_rcap = 0
self.sth_rcap = 0
self.lth_mvrv = 0
self.sth_mvrv = 0
# 此“UtxosIf”类使用默认值初始化大量属性。以下是属性的摘要
#
# - 与平衡相关的属性:
# - 'balance_0' 'balance_001' ... 'balance_10000':这些是不同面额比特币的余额计数器。
# - 'balance_amount_0' 'balance_amount_001' ... 'balance_amount_10000':这些是与余额计数器相对应的余额金额。
#
# - 与地址和利润相关的属性:
# - 'profit_addresses':利润计数器地址。
# - 'loss_addresses' 丢失地址的计数器。
# - 与利润率、供应、已实现价格等相关的各种其他属性
#
#
# - 与持有人及其余额相关的属性:
# - 不同时间间隔的持有者计数器('holder_0'、'holder_1'、...、'holder_3960')。
# - 每个持有人的相应余额属性。
#
# - 与价格和交易相关的属性:
# - 用于存储价格和交易金额的字典('price_buy'、'price_buy_amount'、'diff_sell'、'diff_sell_amount'、'profit_sell'、'profit_sell_amount')。
#
# - 与余额随时间变化相关的属性:
# - 用于存储不同时间间隔的余额变化的字典('balance_0_days'、'balance_001_days'、...、'balance_amount_10000_days')。
#
# - 与
# MongoDB
# 连接和其他指标相关的属性:
# - 连接到MongoDB数据库'mc''mdb')。
# - 与利润、亏损、已实现资本化等相关的指标
#
# 此类似乎用于管理与比特币UTXO未花费的交易输出相关的各种指标和数据
def init_db(self):
return pymysql.connect(host="172.17.0.1", port=4419, user="root", password="IeQcJNnagkaFP1Or", database="btcdb",
cursorclass=pymysql.cursors.DictCursor)
# 'init_dbpymysql库来建立连接。
#
# 以下是该方法的作用的细分
#
# 它使用提供的主机、端口、用户名、密码和数据库名称建立与
# MySQL
# 数据库的连接。
def get_vout_addr(self, rpc, txid, vout):
addr = None
addrtype = None
ip = "127.0.0.1"
port = " 8332"
user = "user"
password = "password"
if rpc is None:
rpc = RPC(ip, port, user, password)
tx = None
while True:
try:
tx = rpc.transactions.get_raw_transaction(txid, True)
#break
except:
time.sleep(1)
#print("reconnect")
rpc = RPC(ip, port, user, password)
continue
txouts = tx["vout"]
txout = None
for outone in txouts:
# print(outone, vout)
if outone["n"] == vout:
txout = outone
break
scriptPubKey = txout["scriptPubKey"]
addrtype = scriptPubKey["type"]
#print("get_vout_addr", txid, vout, tx, scriptPubKey, addrtype)
if "address" not in scriptPubKey:
addr = scriptPubKey["hex"]
if scriptPubKey["type"] == "pubkey":
temphex = scriptPubKey["hex"]
try:
if temphex[2:4] == "04":
addr = PublicKey(temphex[2:132]).get_address(False).to_string()
else:
addr = PublicKey(temphex[2:68]).get_address().to_string()
print("pubkey", txid, temphex, addr)
except Exception as e:
print("pubkey exception", txid, vout, temphex, addr, e)
else:
print(scriptPubKey)
else:
addr = scriptPubKey["address"]
# print(addr)
break
return rpc, addr, addrtype
# “UtxosIf”类中的“get_vout_addr”方法旨在检索与给定事务 txid 中的特定事务输出 vout 相对应的地址和地址类型。以下是其功能的细分:
#
# -参数:
# - 'rpc':用于与比特币网络交互的 RPC 类的实例。
# - 'txid':交易 ID。
# - 'vout':事务输出的索引。
#
# -初始化:
# - 它初始化用于 RPC 连接的 IP 地址、端口、用户名和密码的变量。
#
# - RPC连接
# - 如果 'rpc' 参数为 'None',则使用默认 IP、端口、用户名和密码初始化 RPC 连接。
#
# - 交易检索:
# - 它尝试使用 'get_raw_transaction' 方法从 RPC 对象中检索原始事务详细信息。
# - 如果在此过程中出现异常(可能是由于连接问题),它会等待 1 秒钟并重试。
#
# - 提取地址:
# - 一旦获得交易详细信息,它就会遍历交易的输出('vout')以找到特定的输出。
# - 它从输出中提取“scriptPubKey”及其类型。
# - 如果“scriptPubKey”不直接包含地址它会尝试解析它例如如果它是一个公钥脚本
#
# - 返回结果:
# - 最后,它返回 RPC 实例、地址和地址类型。
#
# 方法如下:
#
# '''蟒蛇
# def get_vout_addrself、rpc、txid、vout
# addr = 无
# addrtype = 无
# ip = “127.0.0.1”
# 端口 =“8332”
# user = “用户”
# password = “密码”
# 如果 rpc 为 None
# rpc = RPCip port user password
# tx = 无
# 而 True
# 尝试:
# tx = rpc.transactions.get_raw_transactiontxid 真)
# 除了:
# 时间睡眠1
# rpc = RPCip port user password
# 继续
#
# txouts = tx[“vout”]
# txout = 无
# 对于 TXOUTS 中的 Outone
# if outone[“n”] == vout
# txout = outone
# 破
# scriptPubKey = txout[“scriptPubKey”]
# addrtype = scriptPubKey[“类型”]
#
# 如果 “address” 不在 scriptPubKey 中:
# addr = scriptPubKey[“十六进制”]
# if scriptPubKey[“type”] == “pubkey”
# temphex = scriptPubKey[“十六进制”]
# 尝试:
# 如果 temphex[24] == “04”
# addr = PublicKeytemphex[2132].get_addressFalse.to_string
# 还:
# addr = PublicKeytemphex[268].get_address.to_string
# print“pubkey” txid temphex addr
# 除了 Exception as e
# print“pubkey exception” txid vout temphex addr e
# 还:
# printscriptPubKey
# 还:
# addr = scriptPubKey[“地址”]
#
# 破
#
# 返回 RPC、ADDR、ADdrType
# '''
#
# 此方法可确保从事务输出中正确提取地址和地址类型,从而处理检索过程中的潜在错误
def summary_toplist(self, txid, vout, coinbase, value, height, scriptpubkey, dt, price, dt2):
if value >= 100:
rpc = None
rpc, addr, addrtype = self.get_vout_addr(rpc, txid, vout)
if addrtype is None:
addrtype = "unknown"
if addr is None:
addr = "unknown"
toplist = {}
toplist["txid"] = txid
toplist["vout"] = vout
toplist["coinbase"] = coinbase
toplist["value"] = value
toplist["height"] = height
toplist["scriptpubkey"] = scriptpubkey
toplist["dt"] = dt
toplist["price"] = price
toplist["dt2"] = dt2
toplist["addr"] = addr
toplist["type"] = addrtype
result = self.mdbc_toplist.find_one(toplist)
if result is None or len(result) > 0:
self.mdbc_toplist.insert_one(toplist)
#print(self.mdbc_toplist.find_one())
# 该类中的方法似乎用于汇总和存储有关满足特定条件的事务的信息。以下是该方法的作用summary_toplistUtxosIf
#
# 它需要与交易相关的几个参数、、、。txidvoutcoinbasevalueheightscriptpubkeydtpricedt2
# 它首先检查事务输出 的值是否大于或等于100。value
# 如果该值满足条件则将变量初始化为None。rpc
# 然后它调用该方法来检索与事务输出对应的地址和地址类型。get_vout_addr
# 它创建一个名为的字典其中包含有关交易的各种信息包括其ID、输出索引、是否是
# coinbase交易、其值、区块高度、scriptPubKey、日期时间信息、价格、地址和地址类型。toplist
# 它检查MongoDB集合中是否存在具有相同事务ID和输出索引的记录。如果没有它会将字典插入到集合中。mdbc_toplisttoplist
def summary_balance_days(self, dt, dt2, value, days_out, balance_out):
daysecs = 3600 * 24
days = (dt - dt2)/daysecs
if days < 1:
if "day_0" in days_out:
days_out["day_0"]+=1
balance_out["day_0"] += value
else:
days_out["day_0"]=1
balance_out["day_0"] = value
elif days < 1 * 2:
if "day_1" in days_out:
days_out["day_1"] += 1
balance_out["day_1"] += value
else:
days_out["day_1"] = 1
balance_out["day_1"] = value
elif days < 1 * 3:
if "day_2" in days_out:
days_out["day_2"] += 1
balance_out["day_2"] += value
else:
days_out["day_2"] = 1
balance_out["day_2"] = value
elif days < 1 * 4:
if "day_3" in days_out:
days_out["day_3"] += 1
balance_out["day_3"] += value
else:
days_out["day_3"] = 1
balance_out["day_3"] = value
elif days < 1 * 5:
if "day_4" in days_out:
days_out["day_4"] += 1
balance_out["day_4"] += value
else:
days_out["day_4"] = 1
balance_out["day_4"] = value
elif days < 1 * 6:
if "day_5" in days_out:
days_out["day_5"] += 1
balance_out["day_5"] += value
else:
days_out["day_5"] = 1
balance_out["day_5"] = value
elif days < 1 * 7:
if "day_6" in days_out:
days_out["day_6"] += 1
balance_out["day_6"] += value
else:
days_out["day_6"] = 1
balance_out["day_6"] = value
elif days < 1 * 8:
if "day_7" in days_out:
days_out["day_7"] += 1
balance_out["day_7"] += value
else:
days_out["day_7"] = 1
balance_out["day_7"] = value
elif days < 1 * 9:
if "day_8" in days_out:
days_out["day_8"] += 1
balance_out["day_8"] += value
else:
days_out["day_8"] = 1
balance_out["day_8"] = value
elif days < 1 * 10:
if "day_9" in days_out:
days_out["day_9"] += 1
balance_out["day_9"] += value
else:
days_out["day_9"] = 1
balance_out["day_9"] = value
elif days < 1 * 11:
if "day_10" in days_out:
days_out["day_10"] += 1
balance_out["day_10"] += value
else:
days_out["day_10"] = 1
balance_out["day_10"] = value
elif days < 1 * 12:
if "day_11" in days_out:
days_out["day_11"] += 1
balance_out["day_11"] += value
else:
days_out["day_11"] = 1
balance_out["day_11"] = value
elif days < 1 * 13:
if "day_12" in days_out:
days_out["day_12"] += 1
balance_out["day_12"] += value
else:
days_out["day_12"] = 1
balance_out["day_12"] = value
elif days < 1 * 14:
if "day_13" in days_out:
days_out["day_13"] += 1
balance_out["day_13"] += value
else:
days_out["day_13"] = 1
balance_out["day_13"] = value
elif days < 1 * 15:
if "day_14" in days_out:
days_out["day_14"] += 1
balance_out["day_14"] += value
else:
days_out["day_14"] = 1
balance_out["day_14"] = value
elif days < 1 * 16:
if "day_15" in days_out:
days_out["day_15"] += 1
balance_out["day_15"] += value
else:
days_out["day_15"] = 1
balance_out["day_15"] = value
elif days < 1 * 17:
if "day_16" in days_out:
days_out["day_16"] += 1
balance_out["day_16"] += value
else:
days_out["day_16"] = 1
balance_out["day_16"] = value
elif days < 1 * 18:
if "day_17" in days_out:
days_out["day_17"] += 1
balance_out["day_17"] += value
else:
days_out["day_17"] = 1
balance_out["day_17"] = value
elif days < 1 * 19:
if "day_18" in days_out:
days_out["day_18"] += 1
balance_out["day_18"] += value
else:
days_out["day_18"] = 1
balance_out["day_18"] = value
elif days < 1 * 20:
if "day_19" in days_out:
days_out["day_19"] += 1
balance_out["day_19"] += value
else:
days_out["day_19"] = 1
balance_out["day_19"] = value
elif days < 1 * 21:
if "day_20" in days_out:
days_out["day_20"] += 1
balance_out["day_20"] += value
else:
days_out["day_20"] = 1
balance_out["day_20"] = value
elif days < 1 * 22:
if "day_21" in days_out:
days_out["day_21"] += 1
balance_out["day_21"] += value
else:
days_out["day_21"] = 1
balance_out["day_21"] = value
elif days < 1 * 23:
if "day_22" in days_out:
days_out["day_22"] += 1
balance_out["day_22"] += value
else:
days_out["day_22"] = 1
balance_out["day_22"] = value
elif days < 1 * 24:
if "day_23" in days_out:
days_out["day_23"] += 1
balance_out["day_23"] += value
else:
days_out["day_23"] = 1
balance_out["day_23"] = value
elif days < 1 * 25:
if "day_24" in days_out:
days_out["day_24"] += 1
balance_out["day_24"] += value
else:
days_out["day_24"] = 1
balance_out["day_24"] = value
elif days < 1 * 26:
if "day_25" in days_out:
days_out["day_25"] += 1
balance_out["day_25"] += value
else:
days_out["day_25"] = 1
balance_out["day_25"] = value
elif days < 1 * 27:
if "day_26" in days_out:
days_out["day_26"] += 1
balance_out["day_26"] += value
else:
days_out["day_26"] = 1
balance_out["day_26"] = value
elif days < 1 * 28:
if "day_27" in days_out:
days_out["day_27"] += 1
balance_out["day_27"] += value
else:
days_out["day_27"] = 1
balance_out["day_27"] = value
elif days < 1 * 29:
if "day_28" in days_out:
days_out["day_28"] += 1
balance_out["day_28"] += value
else:
days_out["day_28"] = 1
balance_out["day_28"] = value
elif days < 1 * 30:
if "day_29" in days_out:
days_out["day_29"] += 1
balance_out["day_29"] += value
else:
days_out["day_29"] = 1
balance_out["day_29"] = value
elif days < 1 * 31:
if "day_30" in days_out:
days_out["day_30"] += 1
balance_out["day_30"] += value
else:
days_out["day_30"] = 1
balance_out["day_30"] = value
elif days < 1 * 60:
if "day_60" in days_out:
days_out["day_60"] += 1
balance_out["day_60"] += value
else:
days_out["day_60"] = 1
balance_out["day_60"] = value
elif days < 1 * 90:
if "day_90" in days_out:
days_out["day_90"] += 1
balance_out["day_90"] += value
else:
days_out["day_90"] = 1
balance_out["day_90"] = value
elif days < 1 * 180:
if "day_180" in days_out:
days_out["day_180"] += 1
balance_out["day_180"] += value
else:
days_out["day_180"] = 1
balance_out["day_180"] = value
elif days < 1 * 360:
if "day_360" in days_out:
days_out["day_360"] += 1
balance_out["day_360"] += value
else:
days_out["day_360"] = 1
balance_out["day_360"] = value
elif days < 1 * 540:
if "day_540" in days_out:
days_out["day_540"] += 1
balance_out["day_540"] += value
else:
days_out["day_540"] = 1
balance_out["day_540"] = value
elif days < 1 * 720:
if "day_720" in days_out:
days_out["day_720"] += 1
balance_out["day_720"] += value
else:
days_out["day_720"] = 1
balance_out["day_720"] = value
elif days < 1 * 1080:
if "day_1080" in days_out:
days_out["day_1080"] += 1
balance_out["day_1080"] += value
else:
days_out["day_1080"] = 1
balance_out["day_1080"] = value
elif days < 1 * 1440:
if "day_1440" in days_out:
days_out["day_1440"] += 1
balance_out["day_1440"] += value
else:
days_out["day_1440"] = 1
balance_out["day_1440"] = value
elif days < 1 * 1880:
if "day_1880" in days_out:
days_out["day_1880"] += 1
balance_out["day_1880"] += value
else:
days_out["day_1880"] = 1
balance_out["day_1880"] = value
elif days < 1 * 2160:
if "day_2160" in days_out:
days_out["day_2160"] += 1
balance_out["day_2160"] += value
else:
days_out["day_2160"] = 1
balance_out["day_2160"] = value
elif days < 1 * 2520:
if "day_2520" in days_out:
days_out["day_2520"] += 1
balance_out["day_2520"] += value
else:
days_out["day_2520"] = 1
balance_out["day_2520"] = value
elif days < 1 * 2880:
if "day_2880" in days_out:
days_out["day_2880"] += 1
balance_out["day_2880"] += value
else:
days_out["day_2880"] = 1
balance_out["day_2880"] = value
elif days < 1 * 3240:
if "day_3240" in days_out:
days_out["day_3240"] += 1
balance_out["day_3240"] += value
else:
days_out["day_3240"] = 1
balance_out["day_3240"] = value
elif days < 1 * 3600:
if "day_3600" in days_out:
days_out["day_3600"] += 1
balance_out["day_3600"] += value
else:
days_out["day_3600"] = 1
balance_out["day_3600"] = value
else:
if "day_3960" in days_out:
days_out["day_3960"] += 1
balance_out["day_3960"] += value
else:
days_out["day_3960"] = 1
balance_out["day_3960"] = value
return days_out, balance_out
# “summary_balance_days”功能似乎旨在根据持有余额的天数对余额进行分类。以下是其工作原理的细分
#
# -参数:
# - 'dt':当前日期。
# - “dt2”获取余额的日期。
# - 'value':余额的值。
# - 'days_out':用于存储不同时期余额计数的字典。
# - 'balance_out':存储不同时期累计余额的字典。
#
# - 计算天数:
# - 它通过从当前日期 'dt' 中减去购置日期 'dt2' 来计算余额持有的天数。此值存储在“days”变量中。
#
# - 对余额进行分类:
# - 根据计算的天数,该函数将余额分配给特定类别 'day_X'),其中
# 'X'
# 表示天数。
# - 如果余额持有时间少于一天则将其归类为“day_0”。
# - 如果余额已持有
# 1
# 到
# 30
# 天则分别归类为“day_1”至“day_30”。
# - 如果余额已持有
# 31
# 到
# 60
# 天则将其归类为“day_60”。
# - 如果余额已持有超过
# 3600
# 天(约
# 10
# 年则将其归类为“day_3960”。
#
# - 累积余额:
# - 对于每个类别,该函数递增余额计数 'days_out' 并将余额值添加到累计余额 'balance_out')。
#
# - 返回结果:
# - 返回更新的“days_out”和“balance_out”字典。
# 0.01,0.1,1,10,100,1000,10000,total balance
# new addr, total address
def summary_utxos(self, current_price, txid, vout, coinbase, value, height, scriptpubkey, dt, price, dt2):
self.total_address += 1
self.total_balance += value
self.total_rcap += (value * price)
if coinbase == 1:
self.miner_address += 1
self.miner_balance += value
if current_price > price:
self.uprofit +=(value*(current_price-price))
self.profit_addresses += 1
if current_price <= price:
self.uloss += (value*(price - current_price))
self.loss_addresses += 1
n = int(price / 1000)
n = n * 1000
keystr = "buy" + str(n)
if keystr in self.price_buy:
self.price_buy[keystr] += 1
else:
self.price_buy[keystr] = 1
keystr = "buy_amount" + str(n)
if keystr in self.price_buy_amount:
self.price_buy_amount[keystr] += value
else:
self.price_buy_amount[keystr] = value
diff = current_price - price
n = int(diff / 1000)
n = n * 1000
keystr = "diff" + str(n)
if keystr in self.diff_sell:
self.diff_sell[keystr] += 1
else:
self.diff_sell[keystr] = 1
keystr = "diff_amount" + str(n)
if keystr in self.diff_sell_amount:
self.diff_sell_amount[keystr] += value
else:
self.diff_sell_amount[keystr] = value
try:
profit = (current_price - price)/(price)*10
except:
profit = current_price*10
if int(profit) < 100:
n = int(profit)
keystr = "profit" + str(n)
if keystr in self.profit_sell:
self.profit_sell[keystr] += 1
else:
self.profit_sell[keystr] = 1
keystr = "profit_amount" + str(n)
if keystr in self.profit_sell_amount:
self.profit_sell_amount[keystr] += value
else:
self.profit_sell_amount[keystr] = value
else:
profit = profit/100
n = int(profit)
keystr = "profit10" + str(n)
if keystr in self.profit_sell:
self.profit_sell[keystr] += 1
else:
self.profit_sell[keystr] = 1
keystr = "profit_amount10" + str(n)
if keystr in self.profit_sell_amount:
self.profit_sell_amount[keystr] += value
else:
self.profit_sell_amount[keystr] = value
if value < 0.01:
self.balance_0 += 1
self.balance_amount_0 += value
self.balance_0_days, self.balance_amount_0_days = self.summary_balance_days(self.current_dayutc, dt2, value, self.balance_0_days,
self.balance_amount_0_days)
elif value < 0.1:
self.balance_001 += 1
self.balance_amount_001 += value
self.balance_001_days, self.balance_amount_001_days = self.summary_balance_days(self.current_dayutc, dt2, value,
self.balance_001_days,
self.balance_amount_001_days)
elif value < 1:
self.balance_01 += 1
self.balance_amount_01 += value
self.balance_01_days, self.balance_amount_01_days = self.summary_balance_days(self.current_dayutc, dt2, value, self.balance_01_days,
self.balance_amount_01_days)
elif value < 10:
self.balance_1 += 1
self.balance_amount_1 += value
self.balance_1_days, self.balance_amount_1_days = self.summary_balance_days(self.current_dayutc, dt2, value, self.balance_1_days,
self.balance_amount_1_days)
elif value < 100:
self.balance_10 += 1
self.balance_amount_10 += value
self.balance_10_days, self.balance_amount_10_days = self.summary_balance_days(self.current_dayutc, dt2, value, self.balance_10_days,
self.balance_amount_10_days)
elif value < 1000:
self.balance_100 += 1
self.balance_amount_100 += value
self.balance_100_days, self.balance_amount_100_days = self.summary_balance_days(self.current_dayutc, dt2, value,
self.balance_100_days,
self.balance_amount_100_days)
elif value < 10000:
self.balance_1000 += 1
self.balance_amount_1000 += value
self.balance_1000_days, self.balance_amount_1000_days = self.summary_balance_days(self.current_dayutc, dt2, value,
self.balance_1000_days,
self.balance_amount_1000_days)
else:
self.balance_10000 += 1
self.balance_amount_10000 += value
self.balance_10000_days, self.balance_amount_10000_days = self.summary_balance_days(self.current_dayutc, dt2, value,
self.balance_10000_days,
self.balance_amount_10000_days)
daysecs = 3600 * 24
if self.current_dayutc - dt2 >= 180 * daysecs:
if self.current_dayutc - dt2 <= 365 * daysecs:
self.slrv_6m1y += (value*price)
if self.current_dayutc - dt2 <= daysecs:
self.slrv_24h += (value*price)
if self.current_dayutc - dt2 >= 155*daysecs:
self.lth_nupl += (value*(current_price-price))
self.lth_rcap += (value*price)
self.lth_mv += (value*current_price)
self.lth_supply += value
if current_price > price:
self.lth_profit_supply += value
if current_price < price:
self.lth_loss_supply += value
else:
self.sth_nupl += (value*(price - current_price))
self.sth_rcap += (value * price)
self.sth_mv += (value * current_price)
self.sth_supply += value
if current_price > price:
self.sth_profit_supply += value
if current_price < price:
self.sth_loss_supply += value
if self.current_dayutc - dt2 < daysecs:
self.holder_0 += 1
self.holder_balance_0 += value
elif self.current_dayutc - dt2 < daysecs * 2:
self.holder_1 += 1
self.holder_balance_1 += value
elif self.current_dayutc - dt2 < daysecs * 3:
self.holder_2 += 1
self.holder_balance_2 += value
elif self.current_dayutc - dt2 < daysecs * 4:
self.holder_3 += 1
self.holder_balance_3 += value
elif self.current_dayutc - dt2 < daysecs * 5:
self.holder_4 += 1
self.holder_balance_4 += value
elif self.current_dayutc - dt2 < daysecs * 6:
self.holder_5 += 1
self.holder_balance_5 += value
elif self.current_dayutc - dt2 < daysecs * 7:
self.holder_6 += 1
self.holder_balance_6 += value
elif self.current_dayutc - dt2 < daysecs * 8:
self.holder_7 += 1
self.holder_balance_7 += value
elif self.current_dayutc - dt2 < daysecs * 15:
self.holder_15 += 1
self.holder_balance_15 += value
elif self.current_dayutc - dt2 < daysecs * 30:
self.holder_30 += 1
self.holder_balance_30 += value
elif self.current_dayutc - dt2 < daysecs * 60:
self.holder_60 += 1
self.holder_balance_60 += value
elif self.current_dayutc - dt2 < daysecs * 90:
self.holder_90 += 1
self.holder_balance_90 += value
elif self.current_dayutc - dt2 < daysecs * 180:
self.holder_180 += 1
self.holder_balance_180 += value
elif self.current_dayutc - dt2 < daysecs * 360:
self.holder_360 += 1
self.holder_balance_360 += value
elif self.current_dayutc - dt2 < daysecs * 540:
self.holder_540 += 1
self.holder_balance_540 += value
elif self.current_dayutc - dt2 < daysecs * 720:
self.holder_720 += 1
self.holder_balance_720 += value
elif self.current_dayutc - dt2 < daysecs * 1080:
self.holder_1080 += 1
self.holder_balance_1080 += value
elif self.current_dayutc - dt2 < daysecs * 1440:
self.holder_1440 += 1
self.holder_balance_1440 += value
elif self.current_dayutc - dt2 < daysecs * 1880:
self.holder_1800 += 1
self.holder_balance_1800 += value
elif self.current_dayutc - dt2 < daysecs * 2160:
self.holder_2160 += 1
self.holder_balance_2160 += value
elif self.current_dayutc - dt2 < daysecs * 2520:
self.holder_2520 += 1
self.holder_balance_2520 += value
elif self.current_dayutc - dt2 < daysecs * 2880:
self.holder_2880 += 1
self.holder_balance_2880 += value
elif self.current_dayutc - dt2 < daysecs * 3240:
self.holder_3240 += 1
self.holder_balance_3240 += value
elif self.current_dayutc - dt2 < daysecs * 3600:
self.holder_3600 += 1
self.holder_balance_3600 += value
else:
self.holder_3960 += 1
self.holder_balance_3960 += value
# “summary_utxos”功能似乎是用于分析交易及其相关余额的更大系统的一部分。以下是该函数的功能细分
#
# - ** 更新计数器和总计: **
# - 'self.total_address':递增
# 1
# 以计算地址总数。
# - “self.total_balance”累积总余额。
# - 'self.total_rcap':累计已实现的总资本化(余额 * 价格)。
# - “self.miner_address”和“self.miner_balance”如果交易是
# coinbase
# 交易“coinbase == 1”则增加矿工地址计数并累积矿工余额。
#
# - ** 盈亏计算: **
# - 'self.uprofit'
# 和
# 'self.uloss':如果当前价格分别高于或低于成交价格,则计算并累计未实现损益。
# - “self.profit_addresses”和“self.loss_addresses”统计有未实现盈亏的地址。
#
# - ** 价格分析: **
# - 'n':将价格四舍五入到最接近的千位。
# - 'keystr':根据四舍五入的价格生成密钥。
# - 更新买入价格“self.price_buy”及其相应金额“self.price_buy_amount”的计数器。
# - 计算当前价格和交易价格之间的差额 'diff'),将其四舍五入到最接近的千位,并更新价格差异计数器('self.diff_sell'
# 和
# 'self.diff_sell_amount')。
#
# - ** 利润百分比分析: **
# - 根据当前价格和交易价格之间的差额计算利润百分比(“利润”)。
# - 将利润分类为不同的范围并相应地更新计数器“self.profit_sell”和“self.profit_sell_amount”
#
# - ** 余额分类: **
# - 根据余额的值将余额分类为不同的范围,并相应地更新计数器。
# - 对于每个范围,更新地址计数 'self.balance_X' 和累计余额 'self.balance_amount_X' 的计数器。
#
# - ** 基于时间的分析: **
# - 分析余额被持有的时间“self.summary_balance_days”并相应地更新计数器。
#
# - ** 其他指标: **
# - 根据余额持有的时间长度更新各种指标,例如短期和长期已实现资本化、市场价值、供应、利润和损失。
#
# - ** 持有人分析: **
# - 根据持有余额的时间对持有人进行分类,并更新相应的计数器,以显示持有人的数量及其累计余额。
#
# 总体而言,此功能似乎提供了对交易数据的全面分析,包括与余额、价格、利润和持有人行为相关的各种指标。
def save_db(self):
db_conn = self.init_db()
with db_conn.cursor() as cursor:
sql_insert = 'REPLACE INTO `utxosv3` (`unixdt`, `total_address`, `total_balance`, `total_rcap`, `miner_address`,`miner_balance`, `balance_0`, `balance_001`, `balance_01`, `balance_1`, `balance_10`,`balance_100`, `balance_1000`, `balance_10000`, uprofit, uloss, lthnupl, sthnupl, lthmarketcap, lthrcap, sthmarketcap, sthrcap, lthmvrv, sthmvrv) VALUES (FROM_UNIXTIME(%s), %s, %s, %s, %s, %s,%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'
cursor.execute(sql_insert, (
self.current_dayutc, self.total_address, self.total_balance, self.total_rcap, self.miner_address, self.miner_balance, self.balance_0,
self.balance_001,
self.balance_01, self.balance_1, self.balance_10, self.balance_100, self.balance_1000, self.balance_10000, self.uprofit, self.uloss, self.lth_nupl, self.sth_nupl, self.lth_mv, self.lth_rcap, self.sth_mv, self.sth_rcap, self.lth_mvrv, self.sth_mvrv))
sql_insert = 'REPLACE INTO `utxos3nd` (`unixdt`, `balance_amount_0`, `balance_amount_001`, `balance_amount_01`, `balance_amount_1`, `balance_amount_10`,`balance_amount_100`, `balance_amount_1000`, `balance_amount_10000`) VALUES (FROM_UNIXTIME(%s), %s, %s, %s, %s, %s,%s, %s, %s)'
cursor.execute(sql_insert, (
self.current_dayutc, self.balance_amount_0,
self.balance_amount_001,
self.balance_amount_01, self.balance_amount_1, self.balance_amount_10, self.balance_amount_100, self.balance_amount_1000,
self.balance_amount_10000))
sql_insert = 'REPLACE INTO `holder3` (`unixdt`,`holder_0`,`holder_1`,`holder_2`,`holder_3`,`holder_4`,`holder_5`,`holder_6`,`holder_7`,`holder_15`,`holder_30`,`holder_60`,`holder_90`,`holder_180`,`holder_360`,`holder_540`,`holder_720`,`holder_1080`,`holder_1440`,`holder_1800`,`holder_2160`,`holder_2520`,`holder_2880`,`holder_3240`,`holder_3600`,`holder_3960`) VALUES(FROM_UNIXTIME(%s), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql_insert, (
self.current_dayutc, self.holder_0, self.holder_1, self.holder_2, self.holder_3, self.holder_4, self.holder_5, self.holder_6, self.holder_7,
self.holder_15,
self.holder_30, self.holder_60, self.holder_90, self.holder_180, self.holder_360, self.holder_540, self.holder_720, self.holder_1080,
self.holder_1440,
self.holder_1800, self.holder_2160, self.holder_2520, self.holder_2880, self.holder_3240, self.holder_3600, self.holder_3960))
sql_insert = 'REPLACE INTO `holder_balance3` (`unixdt`,`holder_balance_0`,`holder_balance_1`,`holder_balance_2`,`holder_balance_3`,`holder_balance_4`,`holder_balance_5`,`holder_balance_6`,`holder_balance_7`,`holder_balance_15`,`holder_balance_30`,`holder_balance_60`,`holder_balance_90`,`holder_balance_180`,`holder_balance_360`,`holder_balance_540`,`holder_balance_720`,`holder_balance_1080`,`holder_balance_1440`,`holder_balance_1800`,`holder_balance_2160`,`holder_balance_2520`,`holder_balance_2880`,`holder_balance_3240`,`holder_balance_3600`,`holder_balance_3960`) VALUES(FROM_UNIXTIME(%s), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql_insert, (
self.current_dayutc, self.holder_balance_0, self.holder_balance_1, self.holder_balance_2, self.holder_balance_3,
self.holder_balance_4,
self.holder_balance_5, self.holder_balance_6, self.holder_balance_7, self.holder_balance_15,
self.holder_balance_30, self.holder_balance_60, self.holder_balance_90, self.holder_balance_180, self.holder_balance_360,
self.holder_balance_540, self.holder_balance_720, self.holder_balance_1080, self.holder_balance_1440,
self.holder_balance_1800, self.holder_balance_2160, self.holder_balance_2520, self.holder_balance_2880, self.holder_balance_3240,
self.holder_balance_3600, self.holder_balance_3960))
#v2
if self.loss_addresses > 0:
self.profit_ratio = self.profit_addresses/self.loss_addresses
if self.total_balance > 0:
self.realized_price = self.total_rcap/self.total_balance
if self.sth_loss_supply > 0:
self.sth_profit_ratio = self.sth_profit_supply/self.sth_loss_supply
if self.lth_loss_supply > 0:
self.lth_profit_ratio = self.lth_profit_supply / self.lth_loss_supply
if self.sth_profit_ratio > 0:
self.relative_lth_sth = self.lth_profit_ratio/self.sth_profit_ratio
if self.slrv_6m1y > 0:
self.slrv_ratio = self.slrv_24h/self.slrv_6m1y
sql_insert = 'REPLACE INTO `utxosv4` (`unixdt`,`profit_addresses`,`loss_addresses`,`profit_ratio`,`lth_supply`,`sth_supply`,`realized_price`,`relative_lth_sth`,`lth_profit_supply`,`lth_loss_supply`,`lth_profit_ratio`,`sth_profit_supply`,`sth_loss_supply`,`sth_profit_ratio`,`slrv_ratio`) VALUES(FROM_UNIXTIME(%s), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'
cursor.execute(sql_insert, (self.current_dayutc, self.profit_addresses, self.loss_addresses, self.profit_ratio, self.lth_supply, self.sth_supply, self.realized_price, self.relative_lth_sth, self.lth_profit_supply, self.lth_loss_supply, self.lth_profit_ratio, self.sth_profit_supply, self.sth_loss_supply, self.sth_profit_ratio, self.slrv_ratio))
db_conn.commit()
mc = pymongo.MongoClient("mongodb://10.168.3.192:27018/")
mdb = mc["btcutxos2"]
# mdb.authenticate("root", "123456")
self.price_buy["unixdt"] = int(self.current_dt)
mdbc_buy = mdb["buy"]
mdbc_buy.insert_one(self.price_buy)
print(mdbc_buy.find_one())
self.price_buy_amount["unixdt"] = int(self.current_dt)
mdbc_buy_amount = mdb["buy_amount"]
mdbc_buy_amount.insert_one(self.price_buy_amount)
print(mdbc_buy_amount.find_one())
self.diff_sell["unixdt"] = int(self.current_dt)
mdbc_diff = mdb["diff"]
mdbc_diff.insert_one(self.diff_sell)
print(mdbc_diff.find_one())
self.diff_sell_amount["unixdt"] = int(self.current_dt)
mdbc_diff_amount = mdb["diff_amount"]
mdbc_diff_amount.insert_one(self.diff_sell_amount)
print(mdbc_diff_amount.find_one())
self.profit_sell["unixdt"] = int(self.current_dt)
mdbc_profit = mdb["profit"]
mdbc_profit.insert_one(self.profit_sell)
print(mdbc_profit.find_one())
self.profit_sell_amount["unixdt"] = int(self.current_dt)
mdbc_profit_amount = mdb["profit_amount"]
mdbc_profit_amount.insert_one(self.profit_sell_amount)
print(mdbc_profit_amount.find_one())
self.balance_0_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_0_days"]
mdbc_balance_days.insert_one(self.balance_0_days)
print(mdbc_balance_days.find_one())
self.balance_amount_0_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_0_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_0_days)
print(mdbc_balance_amount_days.find_one())
self.balance_001_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_001_days"]
mdbc_balance_days.insert_one(self.balance_001_days)
print(mdbc_balance_days.find_one())
self.balance_amount_001_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_001_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_001_days)
print(mdbc_balance_amount_days.find_one())
self.balance_01_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_01_days"]
mdbc_balance_days.insert_one(self.balance_01_days)
print(mdbc_balance_days.find_one())
self.balance_amount_01_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_01_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_01_days)
print(mdbc_balance_amount_days.find_one())
self.balance_1_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_1_days"]
mdbc_balance_days.insert_one(self.balance_1_days)
print(mdbc_balance_days.find_one())
self.balance_amount_1_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_1_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_1_days)
print(mdbc_balance_amount_days.find_one())
self.balance_10_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_10_days"]
mdbc_balance_days.insert_one(self.balance_10_days)
print(mdbc_balance_days.find_one())
self.balance_amount_10_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_10_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_10_days)
print(mdbc_balance_amount_days.find_one())
self.balance_100_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_100_days"]
mdbc_balance_days.insert_one(self.balance_100_days)
print(mdbc_balance_days.find_one())
self.balance_amount_100_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_100_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_100_days)
print(mdbc_balance_amount_days.find_one())
self.balance_1000_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_1000_days"]
mdbc_balance_days.insert_one(self.balance_1000_days)
print(mdbc_balance_days.find_one())
self.balance_amount_1000_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_1000_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_1000_days)
print(mdbc_balance_amount_days.find_one())
self.balance_10000_days["unixdt"] = int(self.current_dt)
mdbc_balance_days = mdb["balance_10000_days"]
mdbc_balance_days.insert_one(self.balance_10000_days)
print(mdbc_balance_days.find_one())
self.balance_amount_10000_days["unixdt"] = int(self.current_dt)
mdbc_balance_amount_days = mdb["balance_amount_10000_days"]
mdbc_balance_amount_days.insert_one(self.balance_amount_10000_days)
print(mdbc_balance_amount_days.find_one())
# “save_db”方法负责将分析期间收集的数据保存到数据库和MongoDB实例中。以下是它的作用的细分
# - MySQL数据库 **
# - 使用'init_db'方法连接到MySQL数据库。
# - 使用SQL查询将记录插入或替换到多个表'utxosv1'、'utxos2nd'、'holder'、'holder_balance'和'utxosv2')中。这些表包含用于分析的各种指标和汇总数据。
# - ** MongoDB **
# - 连接到MongoDB实例。
# - 将数据插入多个集合('buy'、'buy_amount'、'diff'、'diff_amount'、'profit'、'profit_amount'、'balance_0_days'、'balance_amount_0_days'
# 等)中,以进行不同类型的分析。
# 对于MongoDB中的每个集合该方法将数据插入到集合中并打印插入的文档以进行验证。
# 此外该方法还会计算和更新一些其他指标如利润率、实现价格、短期和长期持有者的利润率、相对比率等并将它们插入“utxosv2”表中。
# 总体而言,这种方法有助于将分析的数据存储到关系数据库 MySQL 和NoSQL数据库 MongoDB 中,从而便于检索和进一步分析。
def get_history_price(self):
prices = {}
response_price = requests.get(
'https://data.nasdaq.com/api/v3/datatables/QDL/BCHAIN?code=MKPRU;api_key=FZqXog4sR-b7cYnXcRVV')
if response_price.status_code == 200:
#print(response_price.content)
priceweb = ujson.loads(response_price.content)
if "datatable" in priceweb:
priceset = priceweb["datatable"]
if "data" in priceset:
pricedata = priceset["data"]
for price in pricedata:
daystr = price[1]
p = price[2]
dayutc = time.mktime(time.strptime(daystr, "%Y-%m-%d"))
prices[str(int(dayutc))] = float(p)
#print(price, int(dayutc), g_prices[str(int(dayutc))])
return prices
# “get_history_price”方法似乎用于从WebAPI终结点检索历史价格数据。以下是它的作用的细分
# - 初始化一个空字典“prices”来存储历史价格数据。
# - 向指定的API端点发送HTTP GET请求该端点可能提供历史比特币价格数据。
# - 检查响应状态代码是否为200表示响应成功
# - 如果响应成功:
# - 使用“ujson”库解析JSON响应。
# - 检查解析的JSON响应中是否存在键'“dataset''。
# - 如果'“dataset”'存在:
# - 检索“data”' 字段,该字段可能包含历史价格数据点的列表。
# - 遍历列表中的每个价格数据点。
# - 使用'strptime'将日期字符串 'daystr' 解析为Unix时间戳 'dayutc')。
# - 将Unix 时间戳作为键存储在“prices”字典中并将相应的price 'p' 作为值。
# 最后它返回包含历史价格数据的“prices”字典其中Unix时间戳作为键价格作为值
def get_history_price2(self, pricedict):
#pricedict = {}
dayt = time.gmtime()
daystr = time.strftime("%Y", dayt)
year = int(daystr)
end_year = year
while True:
url = ""
if end_year != year:
start_year = end_year
url = "https://data.messari.io/api/v1/assets/bitcoin/metrics/price/time-series?start="
else:
url = "https://data.messari.io/api/v1/assets/bitcoin/metrics/price/time-series?after=" + str(
year) + "-01-01&order=descending&interval=1d"
if end_year != year:
url = url + str(start_year) + "-01-01&end=" + str(end_year) + "-12-31&order=descending&interval=1d"
header_set = {}
header_set["x-messari-api-key"] = "aH2pyj5i4QGo1k1gLxXEbIJ5RJr+FYKLEWk6cRT6RuSc6lRY"
# header_set["Content-Type"] = "application/json"
print(header_set, url)
response_price = requests.get(url, headers=header_set)
# print(response_price)
if response_price.status_code == 200:
# print(response_price.content)
priceweb = ujson.loads(response_price.content)
if "data" in priceweb:
priceset = priceweb["data"]
if "values" in priceset:
valueset = priceset["values"]
if valueset is not None:
for supply in valueset:
dayutc = int(supply[0] / 1000)
s = supply[1]
ret_time = time.gmtime(dayutc)
ret_daystr = time.strftime("%d %b %Y", ret_time)
ret_dayutc = int(time.mktime(time.strptime(ret_daystr, "%d %b %Y")))
pricedict[str(ret_dayutc)] = float(s)
# print(s, dayutc, pricedict[str(dayutc)])
# break
else:
break
else:
break
end_year -= 1
time.sleep(2)
print(pricedict)
return pricedict
# 'get_history
# 初始化与时间相关的变量,包括当前年份。
# 进入一个循环,从当前年份开始,向后循环访问年份。
# 根据当前年份和端点构造一个URL用于获取比特币价格数据。
# 向构造的URL发送HTTP
# GET请求包括标头中的特定API密钥。
# 检查响应状态代码是否为
# 2
# 使用'u 解析 JSON 响应
# 从JSON响应中提取相关价格数据并将其添加到“pricedict”
# 将时间戳转换为人类可读的日期字符串然后转换回Unix时间戳并将它们作为键存储在'pricedic 中
# 在发出下一个请求之前暂停执行2秒以避免API过载。
# 继续此过程,直到遍历所有年份或发生错误。
# 最后它返回“pricedict”
def get_current_price(self):
price = 0
try:
response_price = requests.get(
'https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT')
prices = ujson.loads(response_price.text)
price = float(prices["price"])
print(response_price.text, price)
response_price.close()
# print("price", price)
return price
except:
response_price = requests.get("https://api.coinpaprika.com/v1/tickers/btc-bitcoin")
prices = ujson.loads(response_price.text)
price = float(prices["quotes"]["USD"]["price"])
response_price.close()
return price
# 该函数似乎是一种从特定
# API端点检索比特币当前价格的方法。以下是其功能的细分get_current_price
# 初始化默认值为0的变量。price
# 向指定的URL 发送HTTP
# GET请求以获取当前以美元为单位的比特币价格。'https://bitcoinexplorer.org/api/price/usd'
# 检查响应状态代码是否为200表示响应成功。
# 如果响应成功它将打印响应文本大概是当前价格并在删除逗号并将其转换为浮点数后将其分配给变量。price
# 关闭响应对象。
# 打印检索到的价格以进行调试。
# 返回检索到的价格。
# 此函数实质上是从指定的API端点检索和处理当前比特币价格并将其作为浮点数返回
def get_ht(self):
try:
with open('height_time.csv', mode='r') as f:
reader = csv.reader(f)
height_time = {rows[0]: rows[1] for rows in reader}
'''for key in height_time.keys():
print(key, height_time[key])
break'''
return height_time
return None
except:
return None
# 这get_ht函数似乎从名为“height_time.csv”
# 的CSV文件中读取数据并将其转换为字典其中键取自第一列值取自第二列。以下是其功能的细分
# 尝试在读取模式下打开文件“height_time.csv”
# 初始化名为“height”的字典
# 使用“csv.reade”循环访问CSV文件中的每一行
# 构造一个字典其中每个键值对对应于CSV文件中的一行键取自第一列值取自第二列。
# 返回“height_time
# 如果在文件读取或字典构造过程中发生异常,该函数将返回“无”
# 此函数实质上是从CSV文件中读取数据并将其作为字典返回该字典可能在代码中的其他位置用于进一步处理或分析
def get_day_utc(self, utc_time):
t = time.gmtime(utc_time)
daystr = time.strftime("%d %b %Y", t)
dayutc = int(time.mktime(time.strptime(daystr, "%d %b %Y")))
return dayutc
# 该函数将
# UTC时间戳作为输入并返回表示与该输入时间戳对应的一天 000000UTC 开始的
# UTC时间戳。以下是其功能的细分get_day_utc
# 它接收UTC时间戳作为输入。utc_time
# 它使用将UTC时间戳转换为时间元组。此元组表示UTC中的时间。time.gmtime()
# 它将时间元组格式化为一个字符串以“DD Mon YYYY”
# 例如“2022年1月1日”表示日期。
# 它使用和将此格式化的字符串转换回UTC时间戳。这有效地将时间设置为同一天的
# 000000UTC。time.strptime()
# time.mktime()
# 它返回表示一天开始的UTC时间戳。
# 总体而言此函数可用于将任何UTC时间戳转换为UTC中相应日期的开始
def get_dh_height(self):
try:
with open('daily_height.csv', mode='r') as f:
reader = csv.reader(f)
daily_height = {rows[0]: rows[1] for rows in reader}
return daily_height
return None
except:
print("failed open daily_height.csv")
return None
# 该函数尝试从名为“daily_height.csv”的CSV
# 文件中读取数据并将其转换为字典其中键是日期值是相应的高度。get_dh_height
# 其工作原理如下:
# 它尝试在读取模式下打开文件“daily_height.csv”。
# 如果文件已成功打开,它将使用函数读取其内容,该函数将返回
# CSV文件各行的可迭代对象。csv.reader()
# 然后它将每行转换为键值对其中第一列索引0表示日期第二列索引1表示高度。这是使用字典理解来完成的。
# 返回生成的字典。daily_height
# 如果在此过程中发生任何错误(例如无法打开文件),它会打印一条消息指示失败并返回.
# None
# 此函数可用于从CSV文件中检索每日身高数据以便在程序中进行进一步处理或分析
def get_dh_hash(self):
try:
with open('daily_height.csv', mode='r') as f:
reader = csv.reader(f)
daily_hash = {rows[0]: rows[2] for rows in reader}
return daily_hash
return None
except:
print("failed open daily_height.csv")
return None
# 该函数类似于 但它不是检索高度值而是从同一个CSV
# 文件 “daily_height.csv” 中检索哈希值。get_dh_hashget_dh_height
# 以下是其工作原理的细分:
# 它尝试在读取模式下打开文件“daily_height.csv”。
# 如果文件已成功打开,它将使用函数读取其内容,该函数将返回
# CSV文件各行的可迭代对象。csv.reader()
# 然后它将每行转换为键值对其中第一列索引0表示日期第三列索引2表示哈希值。这是使用字典理解来完成的。
# 返回生成的字典。daily_hash
# 如果在此过程中发生任何错误(例如无法打开文件),它会打印一条消息指示失败并返回.
# None与
# 一样此函数可用于从CSV文件中检索每日哈希数据以便在程序中进一步处理或分析。get_dh_height
def get_daily_height(self):
height = 1
last_dayutc = None
daily_height = self.get_dh_height()
daily_hash = self.get_dh_hash()
#print(daily_height)
#print(daily_hash)
if daily_height is None:
daily_height = {}
daily_hash = {}
else:
if len(daily_height) > 0:
item = daily_height.popitem()
#print(item, type(item[1]))
height = int(item[1])+1
daily_height[item[0]] = int(item[1])
ip = "127.0.0.1"
port = "8332"
user = "user"
password = "password"
rpc = RPC(ip, port, user, password)
while True:
try:
total_height = rpc.blockchain.get_block_count()
break
except Exception as e:
print(f"❌ get_block_count 超时或异常:{e},重试中...")
time.sleep(3)
rpc = RPC(ip, port, user, password) # 重新建立连接
if height >= total_height:
return
prev_height = None
prev_hash = None
while True:
blockh = None
while True:
try:
blockh = rpc.blockchain.get_block_header(height, True)
#print(blockh)
break
except:
time.sleep(1)
#print("reconnect")
rpc = RPC(ip, port, user, password)
if blockh is not None:
block_time = blockh["time"]
block_height = blockh["height"]
block_hash = blockh["hash"]
dayutc = self.get_day_utc(block_time)
if last_dayutc is None:
last_dayutc = dayutc
print(dayutc, last_dayutc)
if dayutc != last_dayutc:
daily_height[str(last_dayutc)] = prev_height
daily_hash[str(last_dayutc)] = prev_hash
last_dayutc = dayutc
#print(dayutc, daily_height[str(dayutc)], daily_hash[str(dayutc)])
prev_height = block_height
prev_hash = block_hash
while True:
try:
total_height = rpc.blockchain.get_block_count()
if height == total_height:
break
else:
height += 1
print("next height " + str(height))
break
except:
time.sleep(1)
#print("reconnect")
rpc = RPC(ip, port, user, password)
if height == total_height:
break
with open('daily_height.csv', 'w') as f:
for key in daily_height.keys():
#print(key)
#print(daily_height[key])
#print(daily_hash[key])
f.write("%s, %s, %s\n" % (key, daily_height[key], daily_hash[key]))
f.close()
# 该函数负责从区块链中检索每日身高数据并将其存储在名为“daily_height.csv”的CSV文件中。其工作原理如下
# get_daily_height
# 它使用默认值1初始化变量并将其设置为 。heightlast_dayutcNone
# 它调用
# 和
# 函数以从CSV文件中检索任何现有的每日高度和哈希数据。如果数据不可用它将初始化空字典。get_dh_heightget_dh_hash
# 如果存在现有的每日身高数据它将检索最后一个条目将身高递增1并使用新的身高值更新字典。
# 它设置了与比特币区块链交互的RPC连接细节。
# 它使用RPC调用检索区块链的总高度。rpc.blockchain.get_block_count()
# 它进入一个循环来获取每个区块高度的区块头,直到达到区块链的总高度。
# 在循环中如果RPC调用期间出现异常它会尝试重新连接从而处理网络问题。
# 对于成功获取的每个区块标头它都会提取区块时间、高度、哈希值和UTC日。
# 如果UTC日发生更改它会使用当天以前的高度和哈希值更新每日高度和哈希字典。
# 它将每日高度和哈希数据写入“daily_height.csv”文件。
# 一旦它处理了所有区块高度,直到区块链的总高度,该函数就会结束。
# 该功能使用最新的区块链信息有效地更新CSV文件中的每日高度和哈希数据方便历史数据分析或程序内的其他目的。
def get_height_timestamp(self):
height = 0
height_time = self.get_ht()
if height_time is None:
height_time = {}
else:
height = len(height_time)
print("exist height", height)
ip = "127.0.0.1"
port = "8332"
user = "user"
password = "password"
rpc = RPC(ip, port, user, password)
while True:
try:
total_height = rpc.blockchain.get_block_count()
break
except Exception as e:
print(f"❌ get_block_count 超时或异常:{e},重试中...")
time.sleep(10)
rpc = RPC(ip, port, user, password) # 重新建立连接
if height >= total_height:
return
#total_height = rpc.blockchain.get_block_count()
# print("last_height", total_height)
while True:
blockh = None
while True:
try:
blockh = rpc.blockchain.get_block_header(height, True)
#print(blockh)
break
except:
time.sleep(1)
print("reconnect")
rpc = RPC(ip, port, user, password)
if blockh is not None:
block_time = blockh["time"]
block_height = blockh["height"]
height_time[str(block_height)] = block_time
#print(str(block_height), height_time[str(block_height)])
while True:
try:
total_height = rpc.blockchain.get_block_count()
if height == total_height:
break
else:
height += 1
print("next height " + str(height))
break
except:
time.sleep(1)
#print("reconnect")
rpc = RPC(ip, port, user, password)
if height == total_height:
break
with open('height_time.csv', 'w') as f:
for key in height_time.keys():
f.write("%s, %s\n" % (key, height_time[key]))
f.close()
# 该函数从区块链中检索区块高度和相应的时间戳并将它们存储在名为“height_time.csv”的CSV文件中。以下是其工作原理的细分
# get_height_timestamp
# 它将变量初始化为0并使用该函数检索现有的高度时间数据。如果不存在任何数据则初始化一个空字典。heightget_ht
# 它设置了与比特币区块链交互的RPC连接细节。
# 它使用RPC调用检索区块链的总高度。rpc.blockchain.get_block_count()
# 如果存在现有的高度时间数据则将变量设置为字典中的条目数。height
# 它进入一个循环来获取每个区块高度的区块头,直到达到区块链的总高度。
# 在循环中如果RPC调用期间出现异常它会尝试重新连接从而处理网络问题。
# 对于每个成功获取的块头,它都会提取块时间和高度,并更新高度时间字典。
# 它将高度时间数据写入“height_time.csv”文件。
# 循环一直持续到它处理完所有区块高度,直到区块链的总高度。
# 该功能有效地将CSV文件中的高度时间数据更新为最新的区块链信息方便程序内的历史数据分析或其他目的。
def handle_utxos(self, prices, ht, check_dayutc):
current_price = 0
#current_price = self.get_current_price()
#if current_price == 0:
# return
connin = sqlite3.connect("utxos.sqlite")
cin = connin.cursor()
cursorin = cin.execute("SELECT * from utxos")
#connout = sqlite3.connect("utxos.db")
#cout = connout.cursor()
#cout.execute('CREATE TABLE IF NOT EXISTS utxos(txid TEXT PRIMARY KEY NOT NULL, vout INT, value INT, coinbase INT, height INT, scriptpubkey TEXT, dt TIMESTAMP, price INT, dt2 TIMESTAMP)')
#connout.commit()
coin_idx = 0
rpc = None
for row in cursorin:
#print(row)
txid = row[0]
vout = row[1]
value = row[2]
coinbase = row[3]
height = row[4]
scriptpubkey = row[5]
dt = ht[str(height)]
#print(dt)
dt2 = time.gmtime(int(dt))
daystr = time.strftime("%d %b %Y", dt2)
dayutc = int(time.mktime(time.strptime(daystr, "%d %b %Y")))
price = 0
dayutc=dayutc-28800
current_price=current_price-28800
print("ceshi",str(dayutc))
print("ceshi2", str(current_price))
if str(dayutc) > str(check_dayutc):
continue
if str(dayutc) in prices:
price = int(prices[str(dayutc)])
else:
print("failed get tx price")
return
if str(check_dayutc) in prices:
current_price = int(prices[str(check_dayutc)])
else:
print("failed get check price")
return
value = value / 100000000
#print(self.current_dayutc, txid, value, coinbase, height, daystr, dayutc, price, current_price)
self.summary_utxos(current_price, txid, vout, coinbase, value, height, scriptpubkey, dt, price, dayutc)
self.summary_toplist(txid, vout, coinbase, value, height, scriptpubkey, dt, price, dayutc)
#sql_insert = 'INSERT INTO utxos VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'
#insert_data = (txid, vout, value, coinbase, height, scriptpubkey, dt, price, dayutc)
#cout.execute(sql_insert, insert_data)
#if coin_idx % (1024 * 1024) == 0:
#print(coin_idx)
#connout.commit()
coin_idx+=1
#connout.commit()
if self.lth_rcap > 0:
self.lth_mvrv = self.lth_mv / self.lth_rcap
if self.sth_rcap > 0:
self.sth_mvrv = self.sth_mv / self.sth_rcap
self.save_db()
cin.close()
#cout.close()
connin.close()
#connout.close()
# 该方法似乎用于处理来自名为“utxos.sqlite”的
# SQLite
# 数据库的未使用的事务输出 UTXO。以下是其功能的细分handle_utxos
# 它需要三个参数包含历史价格的字典包含区块高度和时间戳的字典检查价格的特定日期。priceshtcheck_dayutc
# 它初始化为0和0。current_pricecoin_idx
# 它建立与SQLite
# 数据库的连接并检索用于执行SQL查询的游标。
# 它循环访问从数据库提取的表中的每一行。utxos对于每一行它提取各种属性例如交易
# ID、输出索引 、值、是否是coinbase交易 ()、区块高度 、scriptPubKey 和时间戳 。txidvoutcoinbaseheightscriptpubkeydt
# 它将时间戳转换为人类可读的日期字符串然后转换为UTC时间戳。dtdaystrdayutc
# 它从字典中获取与对应的历史价格并将其分配给变量。dayutcpricesprice
# 它检查字典中是否存在 ,并将其相应的价格分配给 。check_dayutcpricescurrent_price
# 它将UTXO值除以1000000000以将其转换为比特币单位。
# 它调用和方法与相关参数来处理UTXO数据。summary_utxossummary_toplist
# 如有必要根据某些条件进行计算。lth_mvrvsth_mvrv
# 最后它调用该方法将处理后的数据保存到数据库中。save_db
# 它关闭游标和数据库连接。
# 此方法有效地处理来自SQLite数据库的UTXO的处理执行必要的计算和更新并将处理后的数据保存回数据库
def utxos(self, check_dayutc):
self.current_dt = check_dayutc
self.current_dt2 = time.gmtime(int(self.current_dt))
self.current_daystr = time.strftime("%d %b %Y", self.current_dt2)
self.current_dayutc = int(time.mktime(time.strptime(self.current_daystr, "%d %b %Y")))
topliststr = "toplist" + self.current_daystr
print(topliststr)
self.mdbc_toplist = self.mdb[topliststr]
# prices_temp = self.get_history_price()
# prices = self.get_history_price2(prices_temp)
prices_temp=btc_historical_price.prices_temp
prices=btc_historical_price.prices
'''for key in prices.keys():
print(key, prices[key])
break'''
print(prices)
if len(prices) <= 0:
print("failed get price")
return
ht = self.get_ht()
if ht is None:
print("failed get height and time")
return
self.handle_utxos(prices, ht, check_dayutc)
# 该方法似乎负责处理 表示的特定日期的未使用事务输出 UTXO。以下是其功能的摘要utxoscheck_dayutc
#
# 它根据提供的 .check_dayutc
# 它使用 和 方法检索历史价格数据。get_history_priceget_history_price2
# 该方法从纳斯达克 API 检索历史比特币价格数据。get_history_price
# 该方法从 Messari API 检索其他历史价格数据。get_history_price2
# 它使用该方法检索高度和时间戳数据。get_ht
# 它调用该方法以使用检索到的价格和高度数据处理 UTXO。handle_utxos
# 该方法进一步与 SQLite 数据库交互以处理 UTXO 并执行必要的计算。handle_utxos
# 总体而言,该方法协调了获取历史价格和高度数据并使用它来处理特定日期的 UTXO 的过程。如果成功,它将使用处理后的 UTXO 数据更新相关数据库。utxos
if __name__ == '__main__':
if len(sys.argv) > 1:
check_dt = sys.argv[1]
stats = UtxosIf()
setup('mainnet')
stats.get_height_timestamp()
stats.get_daily_height()
daily_hash = stats.get_dh_hash()
#print(daily_hash)
if daily_hash is None:
print("failed get daily height")
else:
os.system("if [ -e utxos.dat ]; then rm utxos.dat; fi")
os.system("if [ -e utxos.sqlite ]; then rm utxos.sqlite; fi")
check_dayutc = int(time.mktime(time.strptime(check_dt, "%Y-%m-%d")))
cmd = "~/bitcoin-29.0/bin/bitcoin-cli -rpcuser=user -rpcpassword=password invalidateblock " + daily_hash[str(check_dayutc)]
os.system(cmd)
print("select ok")
time.sleep(60);
os.system("~/bitcoin-29.0/bin/bitcoin-cli -rpcuser=user -rpcpassword=password dumptxoutset ~/utxos.dat")
print("dumptxoutset ok")
time.sleep(60);
# os.system("./utxo_to_sqlite ./utxos.dat ./utxos.sqlite")
os.system("python3 ~/utxo_to_sqlite.py ~/utxos.dat ~/utxos.sqlite")
print("utxo_to_sqlite ok")
time.sleep(60);
stats.utxos(check_dayutc)
print("utxos stat ok")
cmd = "~/bitcoin-29.0/bin/bitcoin-cli -rpcuser=user -rpcpassword=password reconsiderblock " + daily_hash[str(check_dayutc)]
os.system(cmd)
print("reconsiderblock ok")
# 此脚本似乎基于命令行参数执行与比特币 UTXO未花费的交易输出相关的几个任务。以下是它的作用的细分
# 1. 它检查脚本是否直接运行 '__name__ == '__main__'')。
# 2. 它检查是否提供了命令行参数 'lensys.argv > 1')。
# 3. 它初始化“UtxosIf”类的实例可能包含与处理 UTXO 相关的方法。
# 4. 它使用“设置”功能设置比特币网络(假设为“主网”)。
# 5. 它分别使用“get_height_timestamp”和“get_daily_height”方法检索高度和时间戳数据。
# 6. 它使用“get_dh_hash”方法获取每日哈希数据。
# 7. 如果每日哈希数据可用,则继续进行进一步操作:
# - 如果存在现有的“utxos.dat”和“utxos.sqlite”文件它会删除它们。
# - 它使用比特币 CLI 命令“invalidateblock”使区块失效。
# - 它会等待一段时间(大概是网络处理区块失效)。
# - 它使用比特币CLI命令'dumptxoutset'转储UTXO集。
# - 它再次等待。
# - 它使用“utxo_to_sqlite”脚本将转储的 UTXO 数据转换为 SQLite 数据库。
# - 它使用“utxos”方法处理指定日期的 UTXO。
# - 它使用比特币 CLI 命令“reconsiderblock”重新考虑之前失效的区块。
# 8. 每个步骤都附有指示脚本进度的打印语句。
# 这个脚本似乎是一个更大的系统的一部分该系统与比特币网络交互并执行与UTXO相关的任务。它严重依赖比特币核心软件和命令行界面“bitcoin-cli”