Skip to content

Instantly share code, notes, and snippets.

@matpowel
Last active January 19, 2023 18:13
Show Gist options
  • Save matpowel/d829b3ec92968ac6bda42da6505084ce to your computer and use it in GitHub Desktop.
Save matpowel/d829b3ec92968ac6bda42da6505084ce to your computer and use it in GitHub Desktop.
Automated transformation of Nexo CSV output to Koinly full template format
require 'csv'
if ARGV.empty? || ARGV.length > 2
puts
puts 'Please specific the input file name and optionally output base filename:'
puts ' ruby nexo_export_conversion.rb nexo_transactions.csv output_filename'
puts
puts 'Note that the default output filename is input filename appended with each output format appended, currently:'
puts ' - output_filename_koinly.csv'
puts ' - output_filename_coinstats.csv'
exit
end
def _extract_nexo_row(row)
results = {}
results[:date] = row['Date / Time']
results[:tx] = row['Transaction']
results[:label] = row['Type']
results[:description] = row['Details']
results[:usd] = row['USD Equivalent']&.gsub(/[^0-9.\-]/, '')&.to_f
results[:amount] = row['Amount']&.gsub(/[^0-9.\-]/, '')&.to_f || 0
results[:currency] = row['Currency']
results[:currency] = 'NEXO' if results[:currency] == 'NEXONEXO'
results[:sent_amount] = nil
results[:sent_currency] = nil
if results[:currency]&.include?('/')
results[:sent_currency], results[:currency] = results[:currency].split('/')
results[:sent_amount] = results[:usd] if results[:sent_currency]&.strip&.match?(/^USD/)
end
if results[:sent_amount].nil? && results[:description]&.include?('USD to USDX')
results[:sent_amount] = results[:amount]
results[:sent_currency] = 'USD'
results[:currency] = 'USDX'
end
results
end
infile = ARGV[0]
csv = CSV.parse(File.read(infile), headers: true, skip_blanks: true)
# Koinly
outfile = ARGV[1]
outfile ||= File.join(File.dirname(infile), "#{File.basename(infile, '.csv')}_koinly.csv")
out_csv = CSV.generate do |new_csv|
new_csv << [
'Date',
'Sent Amount',
'Sent Currency',
'Received Amount',
'Received Currency',
'Fee Amount',
'Fee Currency',
'Net Worth Amount',
'Net Worth Currency',
'Label',
'Description',
'TxHash'
]
csv.each do |row|
values = _extract_nexo_row(row)
if values[:amount]&.negative?
values[:sent_currency] = values[:currency]
values[:currency] = nil
values[:sent_amount] = values[:amount]
values[:amount] = 0
end
new_csv << [
values[:date],
values[:sent_amount],
values[:sent_currency],
values[:amount],
values[:currency],
nil,
nil,
values[:usd],
'USD',
values[:label],
values[:description],
values[:tx]
]
end
end
File.write(outfile, out_csv)
# Coinstats
outfile = ARGV[1]
outfile ||= File.join(File.dirname(infile), "#{File.basename(infile, '.csv')}_coinstats.csv")
out_csv = CSV.generate do |new_csv|
new_csv << [
'Coin Symbol',
'Exchange',
'Pair',
'Type',
'Amount',
'Price',
'Fee',
'Date',
'Notes'
]
csv.each do |row|
values = _extract_nexo_row(row)
# Never use negatives for Coinstats
values[:amount] = values[:amount]&.abs
case values[:label]
when 'DepositToExchange'
when 'Exchange Cashback'
values[:label] = :deposit
values[:sent_currency] ||= 'USD'
when 'ExchangeDepositedOn'
next
when 'Exchange'
if values[:currency].include?('USD')
values[:label] = :sell
currency = values[:currency]
values[:currency] = values[:sent_currency]
values[:sent_currency] = currency
else
values[:label] = :buy
end
when 'Interest', 'FixedTermInterest'
values[:label] = :interest_earn
when 'LockingTermDeposit', 'UnlockingTermDeposit'
# Skip these
next
when 'ReferralBonus'
values[:label] = :referral_cashback
when 'Withdrawal'
values[:label] = :withdraw
else
values[:label] = values[:label]&.downcase&.gsub(/\s/, '_')
end
new_csv << [
values[:currency],
'Nexo',
values[:sent_currency],
values[:label],
values[:amount],
nil,
nil,
values[:date],
values[:description]
]
end
end
File.write(outfile, out_csv)
@brennondenny
Copy link

Hello,

When running I'm seeing the following error:

nexo_export_conversion.rb:112:in `block (2 levels) in <main>': undefined method `include?' for nil:NilClass (NoMethodError)

I tried to resolve it by adding the '&' operator but either way the output file seems to be incorrect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment