trades 0.2.1 → 1.0

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.
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