bitshares 0.1.4.pre → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d78dd854953b6dd4587d6325f78ed684d00cc73a
4
- data.tar.gz: 398253f2043e57805839cc50f5a6c1c7be05dc22
3
+ metadata.gz: f764f9e5559cb963c49a566f4467d52af3885c91
4
+ data.tar.gz: 396b6b1131c8cbb7bcc05c12cc4d76602b472423
5
5
  SHA512:
6
- metadata.gz: f847a6172160020215ebc108a63b6cd7b1ab9d0b48e07535996a328f17ec09cfc39ce062ec248c341d449ec2153a7a6cb8062208d9fcc658b0b752228c43d8d6
7
- data.tar.gz: 16d6cdebae1a700b0c9dc6d7708d550d7a1c9611fae623ed395ed3010d9610e4ad37b5b9b4483f10913a8052251cab24a7c682ebcd7abc169d7639a6e6edd244
6
+ metadata.gz: 84208a411b47edd4c940f20db8ed53e3c0f184180579c1d84cb5308ed752599a6622557ec13e5a55dfaabfe109b80159e3dbf6ca0b714505b22a4bd109680a17
7
+ data.tar.gz: b4d3420d3ca5d92200f0f3d67b9f0bdbd54d54a38eb8dcd2a7dabc5e3644f1903389f55806e28ddadf77422d177cfd8ea491ef9025ffd6da5d7fa0d0aa165417
data/README.md CHANGED
@@ -40,8 +40,8 @@ To use this functionality - i.e. with the Wallet class (see below) wallet names
40
40
 
41
41
  **Via a hash**
42
42
  ```Ruby
43
- Bitshares.configure(:wallet => {:name => 'wallet1', :password => 'password1'})
44
- Bitshares.configure(:wallet => {:name => 'wallet2', :password => 'password2'})
43
+ Bitshares.configure(:wallet => {'wallet1' => 'password1'})
44
+ Bitshares.configure(:wallet => {'wallet2' => 'password2'})
45
45
  ...
46
46
  ```
47
47
 
@@ -61,7 +61,8 @@ Bitshares.config # returns the configuration hash
61
61
  ```ruby
62
62
  require 'bitshares'
63
63
 
64
- client = Bitshares::Client.init # The object BitShares RPC client calls are routed to.
64
+ client = CLIENT.init # CLIENT = Bitshares::Client -the object BitShares RPC client calls are routed to.
65
+ client.synced? # if you wish to check whether you are synced with the p2p network.
65
66
  ```
66
67
  Any valid client command can then be issued via a method call with relevant parameters - e.g.
67
68
 
@@ -81,7 +82,7 @@ Data is returned as a hash
81
82
 
82
83
  The blockchain is implemented as a class purely for convenience when calling 'blockchain_' methods:
83
84
  ```Ruby
84
- chain = Bitshares::Blockchain
85
+ chain = Bitshares::Blockchain # CHAIN may be used
85
86
  count = chain.get_block_count # equivalent to client.blockchain_get_block_count
86
87
  ```
87
88
 
@@ -133,42 +134,69 @@ wallet.account_balance # lists the balances for all accounts for this wallet (c.
133
134
 
134
135
  The market class represents the trading (order book and history) for a given an asset-pair - e.g. CNY/BTS. It is instantiated like this:
135
136
  ```Ruby
136
- market = Bitshares::Market.new('CNY', 'BTS')
137
+ cny_bts = Bitshares::Market.new('CNY', 'BTS')
137
138
  ```
138
- The following 'blockchain_market_' client methods may then be used without specifying the quote and base assets again, but with any other optional params the client accepts:
139
+ _Note that the BitShares market convention is that quote asset_id > base asset_id. Reversing the symbols in the above example results in the client returning an 'Invalid Market' error._ An asset's id can be found from the asset hash by using:
139
140
  ```Ruby
140
- market.list_asks # equivalent to blockchain_market_list_asks(quote, base) [limit]
141
- market.list_bids
142
- market.list_covers
143
- market.order_book
144
- market.order_history
145
- market.price_history # required params are: <start time> <duration> optional: [granularity]
141
+ Bitshares::Blockchain.get_asset 'CNY' # for example
142
+ ```
143
+
144
+ The following 'blockchain_market_' client methods may then be used without specifying the quote and base assets again, but with any other optional args the client accepts:
145
+ ```Ruby
146
+ cny_bts.list_asks # equivalent to blockchain_market_list_asks(quote, base) [limit]
147
+ cny_bts.list_bids
148
+ cny_bts.list_covers
149
+ cny_bts.order_book
150
+ cny_bts.order_history
151
+ cny_bts.price_history # required params are: <start time> <duration> optional: [granularity]
146
152
 
147
- market.list_shorts # requires no params and ignores the base asset
148
- get_asset_collateral # requires no params and returns the collateral for the quote asset (ignores the base asset)
153
+ cny_bts.list_shorts # requires no params and ignores the base asset
154
+ cny_bts.get_asset_collateral # requires no params and returns the collateral for the quote asset (ignores the base asset)
149
155
  ```
150
156
 
151
157
  Additionally, the following methods are available:
152
158
  ```Ruby
153
- market.lowest_ask
154
- market.highest_bid
155
- market.mid_price # mean of the above
156
- market.last_fill # price of the last filled order
159
+ cny_bts.lowest_ask
160
+ cny_bts.highest_bid
161
+ cny_bts.mid_price # mean of the above
162
+ cny_bts.last_fill # price of the last filled order
163
+ ```
164
+
165
+ **Trading**
166
+
167
+ So, once we have an account and a market, what do we need to trade - why a Trader of course!
168
+
169
+ ```Ruby
170
+ cny_bts_trader = Bitshares::Trader.new(account, cny_bts) # using examples above
171
+ ```
172
+
173
+ You can now do this:
174
+ ```Ruby
175
+ cny_bts_trader.order_list # lists orders for the account and market - optional limit arg. Returns orders array
176
+
177
+ cny_bts_trader.submit_bid(quantity, price) # buy <quantity> of Market base (BTS here) at <price> (quote/base)
178
+ cny_bts_trader.submit_ask(quantity, price) # sell <quantity> of Market base (BTS here) at <price> (quote/base)
179
+ # both return respective order id
180
+
181
+ cny_bts_trader.cancel_orders(*order_ids) # cancels one or more orders for the account and market
182
+ # returns array of memo's e.g. 'cancel ASK-90189b6e'
157
183
  ```
158
184
 
159
185
  ## Specification & tests
160
186
 
161
- For the full specification please clone this repo and run:
187
+ For the full specification clone this repo and run:
162
188
 
163
189
  `rake spec`
164
190
 
165
- _Important:_ There is currently no sandbox, so the test suite runs on your live client. If this concerns you - and it should :scream: - feel free to browse the code. In particular, the following client 'fixtures' are required for the full test suite to run and pass:
191
+ **Test Requirements**
192
+
193
+ There is currently no test blockchain, so the test suite runs on the live one - orders and all. If this concerns you - and it should :scream: - feel free to browse the test code first. The following client 'fixtures' are required for the full test suite to run and pass:
166
194
 
167
- An empty wallet 'test1', with password 'password1' and an account called 'account-test' (please don't register this account!)
195
+ An empty wallet 'test1', with password 'password1' and an account called 'account-test' *Please don't register this account!*. The account will also need funding with a few BTS as trades/cancellations are 0.5 BTS each. 10 BTS (circa 2.5 cents right now) should be more than enough to run the suite a few times.
168
196
 
169
197
  ## Contributing
170
198
 
171
- Bug reports and pull requests (and feature requests) are welcome on GitHub at https://github.com/MatzFan/bitshares-ruby.
199
+ Bug reports, pull requests (and feature requests) are welcome on GitHub at https://github.com/MatzFan/bitshares-ruby.
172
200
 
173
201
 
174
202
  ## License
@@ -10,10 +10,15 @@ require 'bitshares/blockchain'
10
10
  require 'bitshares/wallet'
11
11
  require 'bitshares/account'
12
12
  require 'bitshares/market'
13
+ require 'bitshares/trader'
14
+
15
+ CLIENT = Bitshares::Client
16
+ CHAIN = Bitshares::Blockchain
13
17
 
14
18
  # stackoverflow.com/questions/6233124/where-to-place-access-config-file-in-gem
15
19
  module Bitshares
16
- @config = {:wallets => {nil => nil}} # name/password key/value pairs
20
+
21
+ @config = {:wallet => {nil => nil}} # name/password key/value pairs
17
22
 
18
23
  @valid_keys = @config.keys
19
24
 
@@ -2,8 +2,6 @@ module Bitshares
2
2
 
3
3
  class Account
4
4
 
5
- CLIENT = Bitshares::Client
6
-
7
5
  attr_reader :wallet, :name
8
6
 
9
7
  def initialize(wallet, name)
@@ -12,7 +10,7 @@ module Bitshares
12
10
  end
13
11
 
14
12
  def method_missing(m, *args)
15
- CLIENT::rpc.request('wallet_account_' + m.to_s, [name] + args)
13
+ CLIENT.request('wallet_account_' + m.to_s, [name] + args)
16
14
  end
17
15
 
18
16
  end
@@ -3,7 +3,7 @@ module Bitshares
3
3
  class Blockchain
4
4
 
5
5
  def self.method_missing(name, *args)
6
- Bitshares::Client::rpc.request('blockchain_' + name.to_s, args)
6
+ CLIENT.request('blockchain_' + name.to_s, args)
7
7
  end
8
8
 
9
9
  end
@@ -2,66 +2,54 @@ module Bitshares
2
2
 
3
3
  class Client
4
4
 
5
+ class Err < RuntimeError; end
6
+
5
7
  def self.init
6
- @user = ENV['BITSHARES_ACCOUNT']
7
- @password = ENV['BITSHARES_PASSWORD']
8
- @@rpc_instance = Bitshares::Client::Rpc.new(@user, @password)
8
+ bitshares_running?
9
+ user = ENV['BITSHARES_ACCOUNT']
10
+ password = ENV['BITSHARES_PASSWORD']
11
+ @uri = URI("http://localhost:#{rpc_http_port}/rpc")
12
+ @req = Net::HTTP::Post.new(@uri)
13
+ @req.content_type = 'application/json'
14
+ @req.basic_auth user, password
9
15
  return self
10
16
  end
11
17
 
12
- def self.rpc
13
- @@rpc_instance
14
- end
15
-
16
18
  def self.synced?
17
19
  blockchain_get_block_count >= self.get_info['blockchain_head_block_num']
18
20
  end
19
21
 
20
22
  def self.method_missing(m, *args)
21
- @@rpc_instance.request(m, args)
23
+ self.request(m, args)
22
24
  end
23
25
 
24
- class Rpc
25
-
26
- class Err < RuntimeError; end
27
-
28
- def initialize(user, password)
29
- bitshares_running?
30
- @uri = URI("http://localhost:#{rpc_http_port}/rpc")
31
- @req = Net::HTTP::Post.new(@uri)
32
- @req.content_type = 'application/json'
33
- @req.basic_auth user, password
34
- end
35
-
36
- def request(m, args = [])
37
- resp = nil
38
- Net::HTTP.start(@uri.hostname, @uri.port) do |http|
39
- @req.body = { method: m, params: args, jsonrpc: '2.0', id: 0 }.to_json
40
- resp = http.request(@req)
41
- end
42
- raise Err, 'Bad credentials' if resp.class == Net::HTTPUnauthorized
43
- result = JSON.parse(resp.body)
44
- e = result['error']
45
- raise Err, JSON.pretty_generate(e), "#{m} #{args.join(' ') if args}" if e
46
- return result['result']
26
+ def self.request(m, args = [])
27
+ resp = nil
28
+ Net::HTTP.start(@uri.hostname, @uri.port) do |http|
29
+ @req.body = { method: m, params: args, jsonrpc: '2.0', id: 0 }.to_json
30
+ resp = http.request(@req)
47
31
  end
32
+ raise Err, 'Bad credentials' if resp.class == Net::HTTPUnauthorized
33
+ result = JSON.parse(resp.body)
34
+ e = result['error']
35
+ raise Err, JSON.pretty_generate(e), "#{m} #{args.join(' ') if args}" if e
36
+ return result['result']
37
+ end
48
38
 
49
- private
50
-
51
- def bitshares_running?
52
- raise Err, 'Server not running!' unless rpc_ports.count == 2
53
- end
39
+ private
54
40
 
55
- def rpc_http_port
56
- rpc_ports.each do |port| # only http RPC port raises a non-empty response
57
- return port unless `curl -s -I -L http://localhost:#{port}`.empty?
58
- end
59
- end
41
+ def self.bitshares_running?
42
+ raise Err, 'Server not running!' unless rpc_ports.count == 2
43
+ end
60
44
 
61
- def rpc_ports # returns bitshares HTTP JSON RPC and JSON RPC server ports
62
- `lsof -iTCP@localhost | grep bitshares`.scan(/:(\d+) \(LISTEN\)/).flatten
45
+ def self.rpc_http_port
46
+ rpc_ports.each do |port| # only http RPC port raises a non-empty response
47
+ return port unless `curl -s -I -L http://localhost:#{port}`.empty?
63
48
  end
49
+ end
64
50
 
51
+ def self.rpc_ports # returns bitshares HTTP JSON RPC and JSON RPC server ports
52
+ `lsof -iTCP@localhost | grep bitshares`.scan(/:(\d+) \(LISTEN\)/).flatten
65
53
  end
66
54
 
67
55
  end
@@ -2,10 +2,7 @@ module Bitshares
2
2
 
3
3
  class Market
4
4
 
5
- class AssetError < RuntimeError; end
6
-
7
- CHAIN = Bitshares::Blockchain
8
- CLIENT = Bitshares::Client
5
+ class Error < RuntimeError; end
9
6
 
10
7
  attr_reader :quote, :base
11
8
 
@@ -13,6 +10,7 @@ module Bitshares
13
10
  [quote, base].each &:upcase!
14
11
  @quote_hash, @base_hash = asset(quote), asset(base)
15
12
  @quote, @base = @quote_hash['symbol'], @base_hash['symbol']
13
+ valid_market?(@quote_hash['id'], @base_hash['id'])
16
14
  @multiplier = multiplier
17
15
  end
18
16
 
@@ -37,21 +35,25 @@ module Bitshares
37
35
  end
38
36
 
39
37
  def list_shorts(limit = nil) # uses quote only, not base
40
- CLIENT::rpc.request('blockchain_market_list_shorts', [quote] + [limit])
38
+ CLIENT.request('blockchain_market_list_shorts', [quote] + [limit])
41
39
  end
42
40
 
43
41
  def get_asset_collateral # uses quote only, not base
44
- CLIENT::rpc.request('blockchain_market_get_asset_collateral', [quote])
42
+ CLIENT.request('blockchain_market_get_asset_collateral', [quote])
45
43
  end
46
44
 
47
45
  def method_missing(m, *args)
48
- CLIENT::rpc.request('blockchain_market_' + m.to_s, [quote, base] + args)
46
+ CLIENT.request('blockchain_market_' + m.to_s, [quote, base] + args)
49
47
  end
50
48
 
51
49
  private
52
50
 
53
51
  def asset(symbol) # returns hash
54
- CHAIN.get_asset(symbol) || (raise AssetError, "Invalid asset: #{symbol}")
52
+ CHAIN.get_asset(symbol) || (raise Error, "Invalid asset: #{symbol}")
53
+ end
54
+
55
+ def valid_market?(quote_id, base_id)
56
+ raise Error, 'Invalid market; quote ID <= base ID' if quote_id <= base_id
55
57
  end
56
58
 
57
59
  def order_hist
@@ -0,0 +1,57 @@
1
+ module Bitshares
2
+
3
+ class Trader
4
+
5
+ class Error < RuntimeError; end
6
+
7
+ WMSA = 'wallet_market_submit_ask'
8
+ WMSB = 'wallet_market_submit_bid'
9
+ WMOL = 'wallet_market_order_list'
10
+ WMCO = 'wallet_market_cancel_orders'
11
+
12
+ attr_reader :account, :market
13
+
14
+ def initialize(account, market)
15
+ @account = account
16
+ @wallet = account.wallet
17
+ @name = account.name
18
+ @market = market
19
+ @base = market.base
20
+ @quote = market.quote
21
+ end
22
+
23
+ def submit_ask(quantity, price, stupid = false)
24
+ @wallet.unlock if @wallet.locked?
25
+ o = CLIENT.request(WMSA, [@name, quantity, @base, price, @quote, stupid])
26
+ o['record_id'] # return order id
27
+ end
28
+
29
+ def submit_bid(quantity, price, stupid = false)
30
+ @wallet.unlock if @wallet.locked?
31
+ o = CLIENT.request(WMSB, [@name, quantity, @base, price, @quote, stupid])
32
+ o['record_id'] # return order id
33
+ end
34
+
35
+ def order_list(limit = '-1')
36
+ CLIENT.request(WMOL, [@quote, @base, limit, @name])
37
+ end
38
+
39
+ def cancel_orders(*id_list)
40
+ @wallet.unlock if @wallet.locked?
41
+ confirm = CLIENT.request(WMCO, id_list)
42
+ confirm['ledger_entries'].map { |e| e['memo'] } # returns 'cancel ASK-xxxxxxxx' first 8 chars of order id
43
+ end
44
+
45
+ def cancel_all
46
+ cancel_orders all_order_ids
47
+ end
48
+
49
+ private
50
+
51
+ def all_order_ids
52
+ order_list.map &:first
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -1,3 +1,3 @@
1
1
  module Bitshares
2
- VERSION = '0.1.4.pre'
2
+ VERSION = '0.1.5'
3
3
  end
@@ -7,7 +7,7 @@ module Bitshares
7
7
  def initialize(name)
8
8
  @name = name
9
9
  @account = nil
10
- @password = Bitshares.config[:wallets][@name.to_sym]
10
+ @password = Bitshares.config[:wallet][@name]
11
11
  end
12
12
 
13
13
  def account(name)
@@ -15,17 +15,17 @@ module Bitshares
15
15
  end
16
16
 
17
17
  def open
18
- Bitshares::Client::rpc.request('wallet_open', [@name])
18
+ CLIENT.request('wallet_open', [@name])
19
19
  end
20
20
 
21
21
  def lock
22
22
  open # must be opened first
23
- Bitshares::Client::rpc.request 'wallet_lock'
23
+ CLIENT.request 'wallet_lock'
24
24
  end
25
25
 
26
26
  def unlock(timeout = 1776)
27
27
  open # must be opened first
28
- Bitshares::Client::rpc.request('wallet_unlock', [timeout, @password])
28
+ CLIENT.request('wallet_unlock', [timeout, @password])
29
29
  end
30
30
 
31
31
  def open?
@@ -46,7 +46,7 @@ module Bitshares
46
46
  end
47
47
 
48
48
  def method_missing(m, *args)
49
- Bitshares::Client::rpc.request('wallet_' + m.to_s, args)
49
+ CLIENT.request('wallet_' + m.to_s, args)
50
50
  end
51
51
 
52
52
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitshares
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4.pre
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruce Steedman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-08-12 00:00:00.000000000 Z
11
+ date: 2015-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,6 +102,7 @@ files:
102
102
  - lib/bitshares/blockchain.rb
103
103
  - lib/bitshares/client.rb
104
104
  - lib/bitshares/market.rb
105
+ - lib/bitshares/trader.rb
105
106
  - lib/bitshares/version.rb
106
107
  - lib/bitshares/wallet.rb
107
108
  homepage:
@@ -119,9 +120,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
120
  version: '0'
120
121
  required_rubygems_version: !ruby/object:Gem::Requirement
121
122
  requirements:
122
- - - ">"
123
+ - - ">="
123
124
  - !ruby/object:Gem::Version
124
- version: 1.3.1
125
+ version: '0'
125
126
  requirements: []
126
127
  rubyforge_project:
127
128
  rubygems_version: 2.4.8