1730 lines
78 KiB
Python
1730 lines
78 KiB
Python
|
# 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_addr(self、rpc、txid、vout):
|
|||
|
# addr = 无
|
|||
|
# addrtype = 无
|
|||
|
# ip = “127.0.0.1”
|
|||
|
# 端口 =“8332”
|
|||
|
# user = “用户”
|
|||
|
# password = “密码”
|
|||
|
# 如果 rpc 为 None:
|
|||
|
# rpc = RPC(ip, port, user, password)
|
|||
|
# tx = 无
|
|||
|
# 而 True:
|
|||
|
# 尝试:
|
|||
|
# tx = rpc.transactions.get_raw_transaction(txid, 真)
|
|||
|
# 除了:
|
|||
|
# 时间睡眠(1)
|
|||
|
# rpc = RPC(ip, 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[2:4] == “04”:
|
|||
|
# addr = PublicKey(temphex[2:132]).get_address(False).to_string()
|
|||
|
# 还:
|
|||
|
# addr = PublicKey(temphex[2:68]).get_address().to_string()
|
|||
|
# print(“pubkey”, txid, temphex, addr)
|
|||
|
# 除了 Exception as e:
|
|||
|
# print(“pubkey exception”, txid, vout, temphex, addr, e)
|
|||
|
# 还:
|
|||
|
# print(scriptPubKey)
|
|||
|
# 还:
|
|||
|
# 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时间戳作为输入,并返回表示与该输入时间戳对应的一天 (00:00:00UTC) 开始的
|
|||
|
# UTC时间戳。以下是其功能的细分:get_day_utc
|
|||
|
# 它接收UTC时间戳作为输入。utc_time
|
|||
|
# 它使用将UTC时间戳转换为时间元组。此元组表示UTC中的时间。time.gmtime()
|
|||
|
# 它将时间元组格式化为一个字符串,以“DD Mon YYYY”
|
|||
|
# (例如,“2022年1月1日”)表示日期。
|
|||
|
# 它使用和将此格式化的字符串转换回UTC时间戳。这有效地将时间设置为同一天的
|
|||
|
# 00:00:00UTC。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. 它检查是否提供了命令行参数 ('len(sys.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”)
|