trades 0.2.1 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/trades CHANGED
@@ -1,9 +1,54 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- require 'trades'
2
+ # encoding: utf-8
4
3
 
5
4
  begin
6
- Trades.new ARGV
7
- rescue SystemExit, Interrupt
8
- puts "\nQuitting..."
5
+ require 'bundler/setup'
6
+ require 'colored'
7
+ require 'optparse'
8
+ require 'socket'
9
+ require 'trades'
10
+
11
+ options = TradeOptions.parse(ARGV)
12
+
13
+ # Connect to Bitcoincharts.com
14
+ puts "Connecting to bitcoincharts.com..."
15
+ if socket = TCPSocket.open("bitcoincharts.com", 27007)
16
+ puts "Connected.\n".green
17
+ puts "Market | Time | Currency | Price | Volume"
18
+
19
+ options.logger.info "Trades has been started.\n" if options.log
20
+ end
21
+
22
+ last_price = {}
23
+
24
+ while data = socket.gets do
25
+ trade = Trade.new data
26
+
27
+ # Check if the trade should be displayed
28
+ if options.filter == :markets && options.markets.length > 0
29
+ next unless options.markets.include? trade.market
30
+ end
31
+ if options.filter == :currencies && options.currencies.length > 0
32
+ next unless options.currencies.include? trade.currency
33
+ end
34
+
35
+ # Compare price of this trade with last trade
36
+ unless last_price[trade.market].nil?
37
+ price = trade.price # we need to save an uncolored copy later
38
+ trade.price.green if price > last_price[trade.market]
39
+ trade.price.red if price < last_price[trade.market]
40
+ last_price[trade.market] = price
41
+ end
42
+
43
+ puts trade
44
+ options.logger.info trade if options.log
45
+ end
46
+ rescue Interrupt
47
+ puts " Disconnecting..."
48
+
49
+ options.logger.info "\nTrades has been closed.\n\n" if options.log
50
+ rescue OptionParser::ParseError => error
51
+ puts "Something went wrong".red + "\n#{error}\n\nType 'trades -h' for help"
52
+ rescue => error
53
+ puts "Disconnected: #{error}"
9
54
  end
data/lib/trades.rb CHANGED
@@ -1,54 +1,2 @@
1
- require 'rubygems'
2
- require 'socket'
3
- require 'json'
4
- require 'colored'
5
-
6
- class Trades
7
- def initialize(args = [])
8
- begin
9
- puts "Connecting to bitcoincharts.com..."
10
- @socket = TCPSocket.open("bitcoincharts.com", 27007)
11
- @markets = []
12
- @last_prices = {}
13
-
14
- # Convert the market names to lowercase
15
- # (CHANGE THIS TO CASE INSENSITIVE REGEX)
16
- args.each do |x| @markets.push(x.downcase) end
17
- args.clear # no need to keep them in memory
18
-
19
- # thUSD | 2011-06-27 23:00:55 | USD | 17.05 | 0.5 |
20
- puts "Exchange | Date and time | Currency | Price | Volume |"
21
-
22
- self.loop
23
- rescue
24
- puts "Error: #{$!}"
25
- end
26
- end
27
-
28
- def loop
29
- while data = @socket.gets do
30
- if data.length > 0 then
31
- j = JSON.parse(data.strip.tr("\x00", '')) # Delete all \x00 weirdness
32
-
33
- if @markets.empty? or @markets.include?(j['symbol'].downcase) then
34
- line = j['symbol'].ljust(15) + "| " # market
35
- line += Time.at(j['timestamp']).strftime("%Y-%m-%d %H:%M:%S") + " | "
36
- line += j['currency'].ljust(9) + "| " # currency
37
-
38
- # Price: display higher price in green / lower price in red
39
- current_price = j['price'].round(2)
40
- last_price = @last_prices[j['symbol']].to_f # Its nil on startup
41
- @last_prices[j['symbol']] = current_price # store for next comparison
42
-
43
- price = current_price.to_s.ljust(9)
44
- price = price.green if current_price > last_price unless last_price.zero?
45
- price = price.red if current_price < last_price
46
-
47
- line += price + "| " + j['volume'].round(2).to_s.ljust(9) + " |"
48
-
49
- puts line
50
- end
51
- end
52
- end
53
- end
54
- end
1
+ require 'trades/trade'
2
+ require 'trades/options'
@@ -0,0 +1,97 @@
1
+ require 'ostruct'
2
+ require 'logger'
3
+
4
+ class TradeOptions
5
+ # Define markets, market aliases and currencies
6
+ MARKETS = %w[mtgoxUSD thUSD mtgoxEUR virwoxSLL mtgoxGBP intrsngGBP
7
+ virtexCAD btceUSD cbxUSD btcexUSD btcdeEUR wbxAUD mtgoxRUB bitmarketEUR
8
+ mtgoxPLN thEUR mtgoxCAD intrsngUSD mtgoxAUD intrsngEUR btcnCNY thAUD
9
+ bitstampUSD mtgoxHKD intsngPLN bitmarketUSD bitnzNZD thLRUSD thINR rockSSL
10
+ mtgoxSGD b2cUSD aqoinEUR mtgoxSEK ruxumUSD thCLP mrcdBRL mtgoxCNY mtgoxCHF
11
+ mtgoxDKK bitfloorUSD ruxumJPY bitmarketAUD mtgoxJPY ruxumZAR bitmarketPLN
12
+ ruxumSEK ruxumRUB rockEUR mtgoxNZD rockUSD ruxumCHF bbmBRL globalPLN
13
+ globalGBP bitmarketRUB ruxumHUF mtgoxTHB ruxumAUD ruxumEUR globalEUR
14
+ bitmarketGBP ruxumGBP ruxumPLN ruxumSGD ruxumTHB ruxumUAH globalUSD]
15
+ ALIASES = {"mtgox" => "mtgoxUSD", "th" => "thUSD", "tradehill" => "thUSD"}
16
+ CURRENCIES = {
17
+ "usd" => "USD", "dollar" => "USD", "us" => "USD",
18
+ "eur" => "EUR", "euro" => "EUR", "euros" => "EUR",
19
+ "gbp" => "GBP", "pound" => "GBP",
20
+ "ssl" => "SSL", "secondlife" => "SSL",
21
+ "cny" => "CNY",
22
+ "cad" => "CAD", "canadian" => "CAD",
23
+ "aud" => "AUD", "australian" => "AUD", "aus" => "AUD",
24
+ "rub" => "RUB", "russian" => "RUB", "rubble" => "RUB",
25
+ "pln" => "PLN", "polish" => "PLN",
26
+ "hkd" => "HKD", "hongkong" => "HKD",
27
+ "nzd" => "NZD", "newzealand" => "NZD", "nz" => "NZD",
28
+ "sgd" => "SGD",
29
+ "sek" => "SEK",
30
+ "clp" => "CLP",
31
+ "brl" => "BRL",
32
+ "chf" => "CHF",
33
+ "dkk" => "DKK",
34
+ "jpy" => "JPY", "yen" => "JPY", "japan" => "JPY",
35
+ "zar" => "ZAR",
36
+ "huf" => "HUF",
37
+ "thb" => "THB",
38
+ "uah" => "UAH"
39
+ }
40
+
41
+ def self.parse(args)
42
+ # Default options
43
+ options = OpenStruct.new
44
+ options.filter = :markets
45
+ options.markets = []
46
+ options.currencies = []
47
+
48
+ opts = OptionParser.new do |opts|
49
+ opts.banner = "Usage: trades [options]\n\n"
50
+
51
+ opts.separator "Options:"
52
+
53
+ # Filter on market
54
+ opts.on("-m", "--market MARKET", MARKETS, ALIASES,
55
+ "Filter on MARKET") do |m|
56
+ options.markets << m # << because of multiple currencies
57
+ end
58
+
59
+ # Filter on currency
60
+ opts.on("-c", "--currency CURRENCY", CURRENCIES.values.uniq, CURRENCIES,
61
+ "Filter on CURRENCY") do |c|
62
+ options.filter = :currencies # default is :markets
63
+ options.currencies << c # << because of multiple currencies
64
+ end
65
+
66
+ # Logging
67
+ opts.on("-l", "--log [FILENAME]", "Log the results to FILENAME") do |file|
68
+ file = "/var/log/trades.log" if file.nil?
69
+ options.log = true
70
+ options.logger = Logger.new File.new(file, 'a+')
71
+ options.logger.formatter = proc { |s, d, p, m| "#{m}\n" }
72
+ end
73
+
74
+ # Help
75
+ opts.on_tail("-h", "--help", "Show this message") do
76
+ puts "#{opts}\n\nMore info: https://github.com/britishtea/Trades"
77
+ exit
78
+ end
79
+
80
+ # List of markets
81
+ opts.on_tail("--markets", "Show a list of all markets") do
82
+ puts "Markets: #{MARKETS.join ', '}\n\nAliases:"
83
+ ALIASES.each { |x,y| puts "#{x} for #{y}" }
84
+ exit
85
+ end
86
+
87
+ # List of currencies
88
+ opts.on_tail("--currencies", "Show a list of all currencies") do
89
+ puts "Currencies: #{CURRENCIES.values.uniq.join ', '}"
90
+ exit
91
+ end
92
+ end
93
+
94
+ opts.parse!(args)
95
+ options
96
+ end
97
+ end
@@ -0,0 +1,35 @@
1
+ require 'json'
2
+
3
+ class Trade
4
+ attr_reader :id
5
+ attr_reader :market
6
+ attr_reader :timestamp
7
+ attr_reader :currency
8
+ attr_reader :volume
9
+
10
+ attr_accessor :price
11
+
12
+ def initialize(data)
13
+ parsed = JSON.parse data.strip.tr("\x00", '')
14
+ @id = parsed['id']
15
+ @market = parsed['symbol']
16
+ @timestamp = parsed['timestamp']
17
+ @currency = parsed['symbol'][-3, 3]
18
+ @price = parsed['price']
19
+ @volume = parsed['volume']
20
+ end
21
+
22
+ def timestamp(show_date = false)
23
+ format = show_date ? "%Y-%m-%d %H:%M:%S" : "%H:%M:%S"
24
+ Time.at(@timestamp).strftime(format)
25
+ end
26
+
27
+ def price(decimals = 4)
28
+ @price.round(decimals)
29
+ end
30
+
31
+ def to_s
32
+ "#{@market.ljust(15)} | #{timestamp()} | #{@currency.ljust(9)} | " +
33
+ "#{price().to_s.ljust(9)} | #{@volume.to_s}"
34
+ end
35
+ end
data/tests/trade.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'bundler/setup'
2
+ require 'colored'
3
+ require 'minitest/spec'
4
+ require 'minitest/autorun'
5
+ require 'trades/trade'
6
+
7
+ describe Trade do
8
+ before do
9
+ json = '{"volume": 1.26934, "timestamp": 1321111130,
10
+ "price": 2.998, "symbol": "btceUSD", "id": 15366282}'
11
+ @trade = Trade.new(json)
12
+ end
13
+
14
+ it "should have attributes of the appropriate type" do
15
+ @trade.id.must_be_kind_of Integer
16
+ @trade.market.must_be_kind_of String
17
+ @trade.timestamp.must_be_kind_of String
18
+ @trade.currency.must_be_kind_of String
19
+ @trade.currency.length.must_be :==, 3
20
+ @trade.price.must_be_kind_of Float
21
+ @trade.volume.must_be_kind_of Float
22
+ end
23
+
24
+ it "should have timestamps in the correct formats" do
25
+ @trade.timestamp(true).must_be :==, "2011-11-12 16:18:50"
26
+ @trade.timestamp(false).must_be :==, "16:18:50"
27
+ end
28
+
29
+ it "should have an option to specify decimals for the price attribute" do
30
+ @trade.price(2).must_be :==, 3.00
31
+ end
32
+
33
+ it "should output a nicely formatted string" do
34
+ regex = /(.{15}) \| ((\d{4}-\d{2}-\d{2} )?\d{2}:\d{2}:\d{2}) \| ([a-zA-z ]{9}) \| ([0-9 \.]{9}) \| ([0-9 \.]+)/i
35
+ @trade.to_s.must_match regex
36
+ end
37
+ end
metadata CHANGED
@@ -1,78 +1,85 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: trades
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
4
5
  prerelease:
5
- version: 0.2.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Waxjar
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-07-04 00:00:00 +02:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: json
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
12
+ date: 2011-11-16 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &2156540440 !ruby/object:Gem::Requirement
20
17
  none: false
21
- requirements:
18
+ requirements:
22
19
  - - ~>
23
- - !ruby/object:Gem::Version
24
- version: 1.5.3
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
25
22
  type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
23
+ prerelease: false
24
+ version_requirements: *2156540440
25
+ - !ruby/object:Gem::Dependency
28
26
  name: colored
27
+ requirement: &2156539960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
33
+ type: :runtime
29
34
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
35
+ version_requirements: *2156539960
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ requirement: &2156562520 !ruby/object:Gem::Requirement
31
39
  none: false
32
- requirements:
40
+ requirements:
33
41
  - - ~>
34
- - !ruby/object:Gem::Version
35
- version: "1.2"
42
+ - !ruby/object:Gem::Version
43
+ version: 1.6.1
36
44
  type: :runtime
37
- version_requirements: *id002
38
- description: Displays the trades that Bitcoincharts monitors nicely
45
+ prerelease: false
46
+ version_requirements: *2156562520
47
+ description: Displays the trading data that Bitcoincharts monitors nicely
39
48
  email:
40
- executables:
49
+ executables:
41
50
  - trades
42
51
  extensions: []
43
-
44
52
  extra_rdoc_files: []
45
-
46
- files:
53
+ files:
47
54
  - lib/trades.rb
55
+ - lib/trades/options.rb
56
+ - lib/trades/trade.rb
57
+ - tests/trade.rb
48
58
  - bin/trades
49
- has_rdoc: true
50
- homepage:
59
+ homepage: https://github.com/britishtea/Trades
51
60
  licenses: []
52
-
53
61
  post_install_message:
54
62
  rdoc_options: []
55
-
56
- require_paths:
63
+ require_paths:
57
64
  - lib
58
- required_ruby_version: !ruby/object:Gem::Requirement
65
+ required_ruby_version: !ruby/object:Gem::Requirement
59
66
  none: false
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: "0"
64
- required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
72
  none: false
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: "0"
70
- requirements: []
71
-
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements:
78
+ - Ruby version 1.9.2 or higher
72
79
  rubyforge_project:
73
- rubygems_version: 1.6.2
80
+ rubygems_version: 1.8.11
74
81
  signing_key:
75
82
  specification_version: 3
76
- summary: Nice trading data
77
- test_files: []
78
-
83
+ summary: Bitcoin trading data on the command line
84
+ test_files:
85
+ - tests/trade.rb