Skip to content

Commit

Permalink
contrib: add clboss-earnings-history and clboss-recent-earnings scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
ksedgwic committed Sep 9, 2024
1 parent 806bfcf commit c3d679d
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
clboss
/clboss
create-tarball
dev-boltz-api
dev-boltz
Expand Down
210 changes: 210 additions & 0 deletions contrib/clboss-earnings-history
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#!/usr/bin/env python3

import subprocess
import argparse
import json
from datetime import datetime
from tabulate import tabulate
from clboss.alias_cache import lookup_alias

def run_lightning_cli_command(network_option, command, *args):
try:
result = subprocess.run(['lightning-cli', network_option, command, *args], capture_output=True, text=True, check=True)
return json.loads(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Command '{command}' failed with error: {e}")
except json.JSONDecodeError as e:
print(f"Failed to parse JSON from command '{command}': {e}")
return None

def format_bucket_time(bucket_time):
if bucket_time == 0:
return "Legacy"
else:
return datetime.utcfromtimestamp(bucket_time).strftime('%Y-%m-%d')

def main():
parser = argparse.ArgumentParser(description="Run lightning-cli with specified network")
parser.add_argument('--mainnet', action='store_true', help='Run on mainnet')
parser.add_argument('--testnet', action='store_true', help='Run on testnet')
parser.add_argument('--signet', action='store_true', help='Run on signet')
parser.add_argument('--regtest', action='store_true', help='Run on regtest')
parser.add_argument('--network', help='Set the network explicitly')

parser.add_argument('nodeid', nargs='?', help='The node ID to pass to clboss-earnings-history (optional)')

args = parser.parse_args()

# Reconcile network option
if args.network:
network_option = f'--network={args.network}'
elif args.testnet:
network_option = '--network=testnet'
elif args.signet:
network_option = '--network=signet'
elif args.regtest:
network_option = '--network=regtest'
else:
network_option = '--network=bitcoin' # lightning-cli wants "bitcoin" for mainnet

if args.nodeid:
earnings_data = run_lightning_cli_command(network_option, 'clboss-earnings-history', args.nodeid)
else:
earnings_data = run_lightning_cli_command(network_option, 'clboss-earnings-history')

# Initialize totals
total_net_earnings = 0
total_in_earnings = 0
total_in_forwarded = 0
total_in_expenditures = 0
total_in_rebalanced = 0
total_out_earnings = 0
total_out_forwarded = 0
total_out_expenditures = 0
total_out_rebalanced = 0

# Process and format data
rows = []
for entry in earnings_data['history']:
in_earnings = entry['in_earnings']
in_forwarded = entry['in_forwarded']
in_expenditures = entry['in_expenditures']
in_rebalanced = entry['in_rebalanced']

out_earnings = entry['out_earnings']
out_forwarded = entry['out_forwarded']
out_expenditures = entry['out_expenditures']
out_rebalanced = entry['out_rebalanced']

# Calculate rates with checks for division by zero
in_forwarded_rate = (in_earnings / in_forwarded) * 1_000_000 if in_forwarded != 0 else 0
in_rebalance_rate = (in_expenditures / in_rebalanced) * 1_000_000 if in_rebalanced != 0 else 0
out_forwarded_rate = (out_earnings / out_forwarded) * 1_000_000 if out_forwarded != 0 else 0
out_rebalance_rate = (out_expenditures / out_rebalanced) * 1_000_000 if out_rebalanced != 0 else 0

total_in_earnings += in_earnings
total_in_forwarded += in_forwarded
total_in_expenditures += in_expenditures
total_in_rebalanced += in_rebalanced
total_out_earnings += out_earnings
total_out_forwarded += out_forwarded
total_out_expenditures += out_expenditures
total_out_rebalanced += out_rebalanced

if args.nodeid:
net_earnings = (in_earnings + out_earnings) - (in_expenditures + out_expenditures)
else:
net_earnings = in_earnings - in_expenditures
total_net_earnings += net_earnings

if args.nodeid:
rows.append([
format_bucket_time(entry['bucket_time']),
f"{in_forwarded:,}".replace(',', '_'),
f"{in_forwarded_rate:,.0f}",
f"{in_earnings:,}".replace(',', '_'),
f"{out_forwarded:,}".replace(',', '_'),
f"{out_forwarded_rate:,.0f}",
f"{out_earnings:,}".replace(',', '_'),
f"{in_rebalanced:,}".replace(',', '_'),
f"{in_rebalance_rate:,.0f}",
f"{in_expenditures:,}".replace(',', '_'),
f"{out_rebalanced:,}".replace(',', '_'),
f"{out_rebalance_rate:,.0f}",
f"{out_expenditures:,}".replace(',', '_'),
f"{int(net_earnings):,}".replace(',', '_')
])
else:
rows.append([
format_bucket_time(entry['bucket_time']),
f"{in_forwarded:,}".replace(',', '_'),
f"{in_forwarded_rate:,.0f}",
f"{in_earnings:,}".replace(',', '_'),
f"{in_rebalanced:,}".replace(',', '_'),
f"{in_rebalance_rate:,.0f}",
f"{in_expenditures:,}".replace(',', '_'),
f"{int(net_earnings):,}".replace(',', '_')
])

# Add a header (separator) row
if args.nodeid:
# Show both the incoming and outgoing statistics
headers = [
"Date",
"In Forwarded",
"PPM",
"In Earnings",
"Out Forwarded",
"PPM",
"Out Earnings",
"In Rebalanced",
"PPM",
"In Expense",
"Out Rebalanced",
"PPM",
"Out Expense",
"Net Earnings"
]
else:
# Incoming and outgoing are always the same (balanced)
headers = [
"Date",
"Forwarded",
"PPM",
"Earnings",
"Rebalanced",
"PPM",
"Expense",
"Net Earnings"
]

# Make a separator row before the totals
rows.append(["-" * len(header) for header in headers])

# Append the total row
if args.nodeid:
# Show both the incoming and outgoing statistics
rows.append([
"TOTAL",
f"{total_in_forwarded:,}".replace(',', '_'),
# misleading because legacy numerator only: f"{total_in_forwarded_rate:,.0f}",
f"",
f"{total_in_earnings:,}".replace(',', '_'),
f"{total_out_forwarded:,}".replace(',', '_'),
# misleading because legacy numerator only: f"{total_out_forwarded_rate:,.0f}",
f"",
f"{total_out_earnings:,}".replace(',', '_'),
f"{total_in_rebalanced:,}".replace(',', '_'),
# misleading because legacy: f"{total_in_rebalance_rate:,.0f}",
f"",
f"{total_in_expenditures:,}".replace(',', '_'),
f"{total_out_rebalanced:,}".replace(',', '_'),
# misleading because legacy: f"{total_out_rebalance_rate:,.0f}",
f"",
f"{total_out_expenditures:,}".replace(',', '_'),
f"{int(total_net_earnings):,}".replace(',', '_')
])
else:
# Incoming and outgoing are always the same (balanced)
rows.append([
"TOTAL",
f"{total_in_forwarded:,}".replace(',', '_'),
# misleading because legacy: f"{total_in_forwarded_rate:,.0f}",
f"",
f"{total_in_earnings:,}".replace(',', '_'),
f"{total_in_rebalanced:,}".replace(',', '_'),
# misleading because legacy: f"{total_in_rebalance_rate:,.0f}",
f"",
f"{total_in_expenditures:,}".replace(',', '_'),
f"{int(total_net_earnings):,}".replace(',', '_')
])

if args.nodeid:
alias = lookup_alias(run_lightning_cli_command, network_option, args.nodeid)
print(f"Showing history for {args.nodeid} aka {alias}")


print(tabulate(rows, headers=headers, tablefmt="pretty", stralign="right", numalign="right"))

if __name__ == "__main__":
main()
171 changes: 171 additions & 0 deletions contrib/clboss-recent-earnings
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/usr/bin/env python3

import os
import subprocess
import argparse
import json
from tabulate import tabulate
from clboss.alias_cache import lookup_alias

def run_lightning_cli_command(network_option, command, *args):
try:
result = subprocess.run(['lightning-cli', network_option, command, *args], capture_output=True, text=True, check=True)
return json.loads(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Command '{command}' failed with error: {e}")
except json.JSONDecodeError as e:
print(f"Failed to parse JSON from command '{command}': {e}")
return None

headers = [
"Alias",
"In Forwarded",
"PPM",
"In Earn",
"Out Forwarded",
"PPM",
"Out Earn",
"In Rebal",
"PPM",
"In Exp",
"Out Rebal",
"PPM",
"Out Exp",
"Net Earn",
]

def calculate_net_earnings(data, network_option):
rows = []

# Initialize totals
total_net_earnings = 0
total_in_earnings = 0
total_in_forwarded = 0
total_in_expenditures = 0
total_in_rebalanced = 0
total_out_earnings = 0
total_out_forwarded = 0
total_out_expenditures = 0
total_out_rebalanced = 0

for node, stats in data['recent'].items():
in_earnings = stats['in_earnings']
in_forwarded = stats['in_forwarded']
in_expenditures = stats['in_expenditures']
in_rebalanced = stats['in_rebalanced']

out_earnings = stats['out_earnings']
out_forwarded = stats['out_forwarded']
out_expenditures = stats['out_expenditures']
out_rebalanced = stats['out_rebalanced']

# Skip rows where all values are zero
if (
in_earnings == 0 and in_forwarded == 0 and in_expenditures == 0 and in_rebalanced == 0 and
out_earnings == 0 and out_forwarded == 0 and out_expenditures == 0 and out_rebalanced == 0
):
continue

alias = lookup_alias(run_lightning_cli_command, network_option, node)

in_forwarded_rate = (in_earnings / in_forwarded) * 1_000_000 if in_forwarded != 0 else 0
in_rebalance_rate = (in_expenditures / in_rebalanced) * 1_000_000 if in_rebalanced != 0 else 0
out_forwarded_rate = (out_earnings / out_forwarded) * 1_000_000 if out_forwarded != 0 else 0
out_rebalance_rate = (out_expenditures / out_rebalanced) * 1_000_000 if out_rebalanced != 0 else 0

net_earnings = in_earnings - in_expenditures + out_earnings - out_expenditures

# Update totals
total_net_earnings += net_earnings
total_in_earnings += in_earnings
total_in_forwarded += in_forwarded
total_in_expenditures += in_expenditures
total_in_rebalanced += in_rebalanced
total_out_earnings += out_earnings
total_out_forwarded += out_forwarded
total_out_expenditures += out_expenditures
total_out_rebalanced += out_rebalanced

rows.append([
alias,
f"{in_forwarded:,}".replace(',', '_'),
f"{in_forwarded_rate:,.0f}",
f"{in_earnings:,}".replace(',', '_'),
f"{out_forwarded:,}".replace(',', '_'),
f"{out_forwarded_rate:,.0f}",
f"{out_earnings:,}".replace(',', '_'),
f"{in_rebalanced:,}".replace(',', '_'),
f"{in_rebalance_rate:,.0f}",
f"{in_expenditures:,}".replace(',', '_'),
f"{out_rebalanced:,}".replace(',', '_'),
f"{out_rebalance_rate:,.0f}",
f"{out_expenditures:,}".replace(',', '_'),
f"{net_earnings:,}".replace(',', '_'),
])

avg_in_earnings_rate = (total_in_earnings / total_in_forwarded) * 1_000_000 if total_in_forwarded != 0 else 0
avg_out_earnings_rate = (total_out_earnings / total_out_forwarded) * 1_000_000 if total_out_forwarded != 0 else 0
avg_in_expenditures_rate = (total_in_expenditures / total_in_rebalanced) * 1_000_000 if total_in_rebalanced != 0 else 0
avg_out_expenditures_rate = (total_out_expenditures / total_out_rebalanced) * 1_000_000 if total_out_rebalanced != 0 else 0

# Divide the net earnings total by 2
total_net_earnings /= 2

# Add a separator row
rows.append(["-" * len(header) for header in headers])

# Append the total row
rows.append([
"TOTAL",
f"{total_in_forwarded:,}".replace(',', '_'),
f"{avg_in_earnings_rate:,.0f}",
f"{total_in_earnings:,}".replace(',', '_'),
f"{total_out_forwarded:,}".replace(',', '_'),
f"{avg_out_earnings_rate:,.0f}",
f"{total_out_earnings:,}".replace(',', '_'),
f"{total_in_rebalanced:,}".replace(',', '_'),
f"{avg_in_expenditures_rate:,.0f}",
f"{total_in_expenditures:,}".replace(',', '_'),
f"{total_out_rebalanced:,}".replace(',', '_'),
f"{avg_out_expenditures_rate:,.0f}",
f"{total_out_expenditures:,}".replace(',', '_'),
f"{int(total_net_earnings):,}".replace(',', '_'),
])

return rows

def main():
parser = argparse.ArgumentParser(description="Run lightning-cli with specified network")
parser.add_argument('--mainnet', action='store_true', help='Run on mainnet')
parser.add_argument('--testnet', action='store_true', help='Run on testnet')
parser.add_argument('--signet', action='store_true', help='Run on signet')
parser.add_argument('--regtest', action='store_true', help='Run on regtest')
parser.add_argument('--network', help='Set the network explicitly')

parser.add_argument('days', nargs='?', help='The number of days to pass to clboss-earnings-history (optional)')

args = parser.parse_args()

# Reconcile network option
if args.network:
network_option = f'--network={args.network}'
elif args.testnet:
network_option = '--network=testnet'
elif args.signet:
network_option = '--network=signet'
elif args.regtest:
network_option = '--network=regtest'
else:
network_option = '--network=bitcoin' # lightning-cli wants "bitcoin" for mainnet

if args.days:
earnings_data = run_lightning_cli_command(network_option, 'clboss-recent-earnings', str(args.days))
else:
earnings_data = run_lightning_cli_command(network_option, 'clboss-recent-earnings')

if earnings_data:
rows = calculate_net_earnings(earnings_data, network_option)
print(tabulate(rows, headers=headers, tablefmt="pretty", stralign="right", numalign="right"))

if __name__ == "__main__":
main()
Empty file added contrib/clboss/__init__.py
Empty file.
Loading

0 comments on commit c3d679d

Please sign in to comment.