rapflag 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/Gemfile +2 -0
- data/History.md +5 -0
- data/bin/rapflag +17 -5
- data/fixtures/vcr_cassettes/rapflag.yml +44 -0
- data/lib/rapflag/bitfinex.rb +93 -0
- data/lib/rapflag/config.rb +0 -6
- data/lib/rapflag/history.rb +125 -0
- data/lib/rapflag/poloniex.rb +325 -0
- data/lib/rapflag/version.rb +1 -1
- data/rapflag.gemspec +1 -0
- data/spec/bitfinex_spec.rb +128 -0
- data/spec/poloniex_spec.rb +115 -0
- data/spec/spec_helper.rb +6 -0
- metadata +24 -5
- data/lib/rapflag/fetch.rb +0 -176
- data/spec/rapflag_spec.rb +0 -115
data/lib/rapflag/fetch.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
require 'csv'
|
2
|
-
require 'open-uri'
|
3
|
-
require 'faraday'
|
4
|
-
require 'fileutils'
|
5
|
-
|
6
|
-
module RAPFLAG
|
7
|
-
|
8
|
-
class History
|
9
|
-
attr_reader :history, :wallet, :currency, :btc_to_usd, :bfx_to_usd
|
10
|
-
DATE_FORMAT = '%Y.%m.%d'
|
11
|
-
DATE_TIME_FORMAT = '%Y.%m.%d %H:%M:%S'
|
12
|
-
@@btc_to_usd = {}
|
13
|
-
@@bfx_to_usd = {}
|
14
|
-
|
15
|
-
def initialize(wallet = 'trading', currency = 'USD')
|
16
|
-
@wallet = wallet
|
17
|
-
@currency = currency
|
18
|
-
end
|
19
|
-
|
20
|
-
def get_usd_exchange(date_time = Time.now, from='BTC')
|
21
|
-
return 1.0 if from == 'USD'
|
22
|
-
key = date_time.strftime(DATE_FORMAT)
|
23
|
-
return @@btc_to_usd[key] if from.eql?('BTC') && @@btc_to_usd.size > 0
|
24
|
-
return @@bfx_to_usd[key] if from.eql?('BFX') && @@bfx_to_usd.size > 0
|
25
|
-
|
26
|
-
ms = (date_time.is_a?(Date) ? date_time.to_time : date_time).to_i*1000
|
27
|
-
ms_next_date = ms + (3*24*3600)*1000
|
28
|
-
# this does not work
|
29
|
-
# url = "https://api.bitfinex.com/v2/candles/trade:1D:t#{from}USD/hist?start:#{ms}?end:#{ms_next_date}"
|
30
|
-
url = "https://api.bitfinex.com/v2/candles/trade:1D:t#{from}USD/hist?start:#{ms}?end:#{ms_next_date}"
|
31
|
-
# therefore we just return the most uptodate
|
32
|
-
url = "https://api.bitfinex.com/v2/candles/trade:1D:t#{from}USD/hist?start:#{ms}"
|
33
|
-
puts "Fetching #{date_time}: #{url} #{@@btc_to_usd.size} BTC #{@@bfx_to_usd.size} BFX" if $VERBOSE
|
34
|
-
response = Faraday.get(url)
|
35
|
-
items = eval(response.body)
|
36
|
-
rates = {}
|
37
|
-
items.each do |item|
|
38
|
-
if item.first.eql?(:error)
|
39
|
-
puts "Fetching returned #{item}. Aborting"
|
40
|
-
exit(1)
|
41
|
-
end
|
42
|
-
# http://docs.bitfinex.com/v2/reference#rest-public-candles
|
43
|
-
# field definitions for [ MTS, OPEN, CLOSE, HIGH, LOW, VOLUME ],
|
44
|
-
# MTS int millisecond time stamp
|
45
|
-
# OPEN float First execution during the time frame
|
46
|
-
# CLOSE float Last execution during the time frame
|
47
|
-
# HIGH integer Highest execution during the time frame
|
48
|
-
# LOW float Lowest execution during the timeframe
|
49
|
-
# VOLUME float Quantity of symbol traded within the timeframe
|
50
|
-
# [[1489363200000,1224.4,1211.2,1238,1206.7,6157.96283895],
|
51
|
-
timestamp = Time.at(item.first/1000).strftime(DATE_FORMAT)
|
52
|
-
rates[timestamp] = item[2]
|
53
|
-
end;
|
54
|
-
from.eql?('BTC') ? @@btc_to_usd = rates.clone : @@bfx_to_usd = rates.clone
|
55
|
-
rates[key] ? rates[key] : nil
|
56
|
-
rescue => err
|
57
|
-
puts "Err #{err}"
|
58
|
-
binding.pry if defined?(MiniTest)
|
59
|
-
end
|
60
|
-
|
61
|
-
def fetch_csv_history
|
62
|
-
client = Bitfinex::Client.new
|
63
|
-
@history = []
|
64
|
-
timestamp = Time.now.to_i + 1
|
65
|
-
while true
|
66
|
-
begin
|
67
|
-
partial = client.history(@currency, { :limit => 500, :until => timestamp, :wallet => @wallet})
|
68
|
-
break unless partial && partial.size > 0
|
69
|
-
if partial.is_a?(Hash)
|
70
|
-
puts "Got #{partial['error']} while fetching #{@wallet} #{@currency} until #{Time.at(timestamp)}"
|
71
|
-
exit 3
|
72
|
-
end
|
73
|
-
first_time = Time.at(partial.first['timestamp'].to_i).strftime(DATE_TIME_FORMAT)
|
74
|
-
last_time = Time.at(partial.last['timestamp'].to_i).strftime(DATE_TIME_FORMAT)
|
75
|
-
puts "Feched #{partial.size} @history entries #{first_time} -> #{last_time}" if $VERBOSE
|
76
|
-
timestamp = (partial.last['timestamp'].to_i - 1)
|
77
|
-
@history = @history | partial
|
78
|
-
break if partial.size <= 1
|
79
|
-
rescue => error
|
80
|
-
puts "error #{error}"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
puts "Feched #{@history.size} history entries" if $VERBOSE
|
84
|
-
end
|
85
|
-
|
86
|
-
# Configure the client with the proper KEY/SECRET, you can create a new one from:
|
87
|
-
# https://www.bitfinex.com/api
|
88
|
-
def create_csv_file
|
89
|
-
out_file = "output/#{@wallet}_#{@currency}.csv"
|
90
|
-
FileUtils.makedirs(File.dirname(out_file))
|
91
|
-
CSV.open(out_file,'w',
|
92
|
-
:write_headers=> true,
|
93
|
-
:headers => ['currency',
|
94
|
-
'amount',
|
95
|
-
'balance',
|
96
|
-
'description',
|
97
|
-
'date_time',
|
98
|
-
] #< column header
|
99
|
-
) do |csv|
|
100
|
-
@history.each do | hist_item|
|
101
|
-
csv << [ hist_item['currency'],
|
102
|
-
hist_item['amount'],
|
103
|
-
hist_item['balance'],
|
104
|
-
hist_item['description'],
|
105
|
-
Time.at(hist_item['timestamp'].to_i).strftime(DATE_TIME_FORMAT),
|
106
|
-
]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
sums = {}
|
111
|
-
@history.each do | hist_item|
|
112
|
-
key = /^[^\d]+/.match(hist_item['description'])[0].chomp
|
113
|
-
value = hist_item['amount'].to_f
|
114
|
-
if sums[key]
|
115
|
-
sums[key] += value
|
116
|
-
else
|
117
|
-
sums[key] = value
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
puts
|
122
|
-
puts "Summary for #{@wallet} #{@currency} (#{@history.size} entries}"
|
123
|
-
sums.each do |key, value|
|
124
|
-
puts " #{sprintf('%40s', key)} is #{value}"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
Struct.new("Daily", :date, :amount, :balance, :description, :income)
|
129
|
-
def create_summary
|
130
|
-
@daily = {}
|
131
|
-
@history.sort{|x,y| x['timestamp'] <=> y['timestamp']}.each do | hist_item|
|
132
|
-
date = Time.at(hist_item['timestamp'].to_i).strftime(DATE_FORMAT)
|
133
|
-
info = Struct::Daily.new(date, hist_item['amount'].to_f, hist_item['balance'].to_f, hist_item['description'])
|
134
|
-
amount = hist_item['amount'].to_f
|
135
|
-
balance = hist_item['balance'].to_f
|
136
|
-
if @daily[date]
|
137
|
-
old_balance = @daily[date]
|
138
|
-
existing = @daily[date]
|
139
|
-
else
|
140
|
-
info.income = 0.0
|
141
|
-
existing = info
|
142
|
-
end
|
143
|
-
if /Wire Withdrawal fee|Trading fees for|Margin Funding Payment on wallet/i.match( hist_item['description'])
|
144
|
-
existing.income += amount
|
145
|
-
end
|
146
|
-
existing.balance = balance if balance != 0.0
|
147
|
-
@daily[date] = existing
|
148
|
-
end
|
149
|
-
out_file = "output/#{@wallet}_#{@currency}_summary.csv"
|
150
|
-
FileUtils.makedirs(File.dirname(out_file))
|
151
|
-
CSV.open(out_file,'w',
|
152
|
-
:write_headers=> true,
|
153
|
-
:headers => ['currency',
|
154
|
-
'date',
|
155
|
-
'income',
|
156
|
-
'balance',
|
157
|
-
'rate',
|
158
|
-
'balance_in_usd',
|
159
|
-
] #< column header
|
160
|
-
) do |csv|
|
161
|
-
@daily.each do |date, info|
|
162
|
-
strings = date.split('.')
|
163
|
-
fetch_date = Date.new(strings[0].to_i, strings[1].to_i, strings[2].to_i)
|
164
|
-
rate = get_usd_exchange(fetch_date, @currency)
|
165
|
-
csv << [@currency,
|
166
|
-
date,
|
167
|
-
info.income,
|
168
|
-
info.balance,
|
169
|
-
rate ? rate : nil,
|
170
|
-
rate ? info.balance * get_usd_exchange(fetch_date, @currency) : nil,
|
171
|
-
]
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
data/spec/rapflag_spec.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
require 'rapflag/fetch'
|
4
|
-
require 'vcr'
|
5
|
-
|
6
|
-
VCR.configure do |config|
|
7
|
-
config.cassette_library_dir = "fixtures/vcr_cassettes"
|
8
|
-
config.hook_into :faraday # or :fakeweb
|
9
|
-
end
|
10
|
-
|
11
|
-
CSV_Test_File = File.expand_path(File.join(__FILE__, '..', '..', 'output/exchange_BTC.csv'))
|
12
|
-
SUMMARY_EXCHANGE_BTC_File = File.expand_path(File.join(__FILE__, '..', '..', 'output/exchange_BTC_summary.csv'))
|
13
|
-
SUMMARY_DEPOSIT_BFX_File = File.expand_path(File.join(__FILE__, '..', '..', 'output/deposit_BFX_summary.csv'))
|
14
|
-
|
15
|
-
VCR.eject_cassette # we use insert/eject around each example
|
16
|
-
describe RAPFLAG do
|
17
|
-
# include ServerMockHelper
|
18
|
-
before(:all) do
|
19
|
-
end
|
20
|
-
after(:all) do
|
21
|
-
end
|
22
|
-
context 'bitfinex' do
|
23
|
-
before(:all) do
|
24
|
-
VCR.use_cassette("rapflag", :record => :new_episodes) do
|
25
|
-
FileUtils.rm_f(CSV_Test_File) if File.exist?(CSV_Test_File)
|
26
|
-
FileUtils.rm_f(SUMMARY_DEPOSIT_BFX_File) if File.exist?(SUMMARY_DEPOSIT_BFX_File)
|
27
|
-
FileUtils.rm_f(SUMMARY_EXCHANGE_BTC_File) if File.exist?(CSV_Test_File)
|
28
|
-
expect(File.exist?(CSV_Test_File)).to eql(false)
|
29
|
-
@rap = RAPFLAG::History.new('exchange', 'BTC')
|
30
|
-
@rap.fetch_csv_history
|
31
|
-
@rap.create_csv_file
|
32
|
-
end
|
33
|
-
end
|
34
|
-
context 'history' do
|
35
|
-
it 'should have correct currency' do
|
36
|
-
expect(@rap.currency).to eql('BTC')
|
37
|
-
end
|
38
|
-
it 'should have correct size' do
|
39
|
-
expect(@rap.history.size).to eql(206)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
context 'bitfinex CSV' do
|
44
|
-
context 'csv' do
|
45
|
-
it 'should have generated a correct CSV file' do
|
46
|
-
expect(File.exist?(CSV_Test_File)).to eql(true)
|
47
|
-
lines = IO.readlines(CSV_Test_File)
|
48
|
-
expect(lines.first.chomp).to eql('currency,amount,balance,description,date_time')
|
49
|
-
expect(lines[1].chomp).to eql(
|
50
|
-
'BTC,-0.00000005,0.0,Transfer of 0.0 BTC from wallet Exchange to Deposit on wallet Exchange,2016.12.03 21:20:47')
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
context 'exchange option --clean' do
|
55
|
-
before(:all) do
|
56
|
-
@date_bfx_1 = Date.new(2017,1,10)
|
57
|
-
@date_btx_1 = Date.new(2017,1,21)
|
58
|
-
@date_btx_2 = Date.new(2017,1,10)
|
59
|
-
VCR.use_cassette("rapflag", :record => :new_episodes) do
|
60
|
-
FileUtils.rm_f(SUMMARY_EXCHANGE_BTC_File) if File.exist?(CSV_Test_File)
|
61
|
-
expect(File.exist?(SUMMARY_EXCHANGE_BTC_File)).to eql(false)
|
62
|
-
@exchange = RAPFLAG::History.new('exchange', 'BTC')
|
63
|
-
@exchange.fetch_csv_history
|
64
|
-
@exchange.create_summary
|
65
|
-
@bfx = @exchange.get_usd_exchange(@date_bfx_1, 'BFX')
|
66
|
-
@btx_1 = @exchange.get_usd_exchange(@date_btx_1, 'BTC')
|
67
|
-
@btx_2 = @exchange.get_usd_exchange(@date_btx_2, 'BTC')
|
68
|
-
end
|
69
|
-
end
|
70
|
-
it 'should have generated a correct summary CSV file' do
|
71
|
-
expect(File.exist?(SUMMARY_EXCHANGE_BTC_File)).to eql(true)
|
72
|
-
lines = IO.readlines(SUMMARY_EXCHANGE_BTC_File)
|
73
|
-
expect(lines.first.chomp).to eql('currency,date,income,balance,rate,balance_in_usd')
|
74
|
-
expect(lines[1].chomp).to eql('BTC,2016.01.15,0.0,8.99788147,,')
|
75
|
-
expect(lines[-1].chomp).to eql('BTC,2016.12.03,0.0,0.0,765.46,0.0')
|
76
|
-
end
|
77
|
-
it 'should have NOT have generated a correct summary deposit BFX CSV file' do
|
78
|
-
expect(File.exist?(SUMMARY_DEPOSIT_BFX_File)).to eql(false)
|
79
|
-
end
|
80
|
-
it 'should have the correct BTC -> USD rate' do
|
81
|
-
expect(@btx_1).to eql 924.02
|
82
|
-
expect(@btx_2).to eql 905.76
|
83
|
-
end
|
84
|
-
it 'should have the correct BFX -> USD rate' do
|
85
|
-
expect(@bfx).to eql 0.5697
|
86
|
-
end
|
87
|
-
end
|
88
|
-
context 'deposit option --clean' do
|
89
|
-
before(:all) do
|
90
|
-
FileUtils.rm_f(SUMMARY_EXCHANGE_BTC_File) if File.exist?(SUMMARY_EXCHANGE_BTC_File)
|
91
|
-
FileUtils.rm_f(SUMMARY_DEPOSIT_BFX_File) if File.exist?(CSV_Test_File)
|
92
|
-
@date_bfx_1 = Date.new(2017,1,10)
|
93
|
-
@date_btx_1 = Date.new(2017,1,21)
|
94
|
-
@date_btx_2 = Date.new(2017,1,10)
|
95
|
-
VCR.use_cassette("rapflag", :record => :new_episodes) do
|
96
|
-
expect(File.exist?(SUMMARY_DEPOSIT_BFX_File)).to eql(false)
|
97
|
-
@deposit = RAPFLAG::History.new('deposit', 'BFX')
|
98
|
-
@deposit.fetch_csv_history
|
99
|
-
@deposit.create_summary
|
100
|
-
end
|
101
|
-
end
|
102
|
-
it 'should have NOT generated a exchange BTC summary CSV file' do
|
103
|
-
expect(File.exist?(SUMMARY_EXCHANGE_BTC_File)).to eql(false)
|
104
|
-
end
|
105
|
-
it 'should have NOT generated a correct summary CSV file' do
|
106
|
-
expect(File.exist?(SUMMARY_DEPOSIT_BFX_File)).to eql(true)
|
107
|
-
lines = IO.readlines(SUMMARY_DEPOSIT_BFX_File)
|
108
|
-
expect(lines.first.chomp).to eql('currency,date,income,balance,rate,balance_in_usd')
|
109
|
-
expect(lines[1].chomp).to eql('BFX,2016.01.15,0.0,8.99788147,,')
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
# https://api.bitfinex.com/v2/candles/trade:1D:tBTCUSD/hist
|
114
|
-
# [[1489363200000,1224.4,1211.2,1238,1206.7,6157.96283895],
|
115
|
-
# [1489276800000,1172.5,1224.4,1232.7,1166.8,18976.8181757]
|