rapflag 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|