alpaca-trade-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0745d9ff9c3a0a67985cbccd1f39490dc2cbd5ad4e49fc84bfe5ce303b91820
4
- data.tar.gz: 4c6958398bbbedad4e86fb229d36377a922dbb4b16bd747d8013949c616ec06e
3
+ metadata.gz: eb5dd189cbc0f77a733ae7a00b6a3448f8071b89bc47f90b749d64c1a34d2709
4
+ data.tar.gz: f5a81f245c4bd2de6b2670cb07d3dfa80988cb1e7eeec8e794969a35493a890e
5
5
  SHA512:
6
- metadata.gz: 1d3ddbc1adc6fb0a78e400fa52505413170ef6adfe19f03dd203d5d90823f0b81cb5d9f909902756e2b5b4d13104d99ead36a7e200b21e0d590f9c195b612faa
7
- data.tar.gz: ea47ae148c14210bcd49c5c40d6a810a7593a45df0e35606964626b0d4b5b9b9956148795f5606077a88aabc14dfb8086b7f928771afb77fa27c2c6174b386c4
6
+ metadata.gz: 9e7090ca6b7ab5dbcb57903d3a90538f76abe585c147294ecc00a366c94e07cce9ac4107bcc537396553ddf5ab9dff8d4138da27d0404635ff9651cdee54755e
7
+ data.tar.gz: fc7b23fa07cb3dad7b9f705ac812a9370c78f92434bdca44beb30e3c891eecd5424aea72fa0173d898e5bb2c16759387fa594763132e60cad9d9c44130540a99
@@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.2.0] - 2019-07-10
8
+ ### Added
9
+ - Implemented Client#calendar.
10
+ - Implemented Client#clock.
11
+ - Added Client#assets.
12
+ - Implemented new methods in Client: new_order, order, orders, position, positions.
13
+ - Implemented Client#cancel_order.
8
14
 
9
15
  ## [0.1.0] - 2019-07-04
10
16
  ### Added
@@ -6,6 +6,11 @@ require 'alpaca/trade/api/configuration'
6
6
  require 'alpaca/trade/api/account'
7
7
  require 'alpaca/trade/api/asset'
8
8
  require 'alpaca/trade/api/bar'
9
+ require 'alpaca/trade/api/calendar'
10
+ require 'alpaca/trade/api/clock'
11
+ require 'alpaca/trade/api/order'
12
+ require 'alpaca/trade/api/position'
13
+
9
14
  require 'alpaca/trade/api/client'
10
15
  require 'alpaca/trade/api/errors'
11
16
 
@@ -15,9 +15,9 @@ module Alpaca
15
15
  @id = json['id']
16
16
  @status = json['status']
17
17
  @currency = json['currency']
18
- @buying_power = json['buying_power']
19
- @cash = json['cash']
20
- @portfolio_value = json['portfolio_value']
18
+ @buying_power = BigDecimal(json['buying_power'])
19
+ @cash = BigDecimal(json['cash'])
20
+ @portfolio_value = BigDecimal(json['portfolio_value'])
21
21
  @pattern_day_trader = json['pattern_day_trader']
22
22
  @trade_suspended_by_user = json['trade_suspended_by_user']
23
23
  @trading_blocked = json['trading_blocked']
@@ -25,12 +25,12 @@ module Alpaca
25
25
  @created_at = json['created_at']
26
26
  @shorting_enabled = json['shorting_enabled']
27
27
  @multiplier = json['multiplier']
28
- @long_market_value = json['long_market_value']
29
- @short_market_value = json['short_market_value']
30
- @equity = json['equity']
31
- @last_equity = json['last_equity']
32
- @initial_margin = json['initial_margin']
33
- @maintenance_margin = json['maintenance_margin']
28
+ @long_market_value = BigDecimal(json['long_market_value'])
29
+ @short_market_value = BigDecimal(json['short_market_value'])
30
+ @equity = BigDecimal(json['equity'])
31
+ @last_equity = BigDecimal(json['last_equity'])
32
+ @initial_margin = BigDecimal(json['initial_margin'])
33
+ @maintenance_margin = BigDecimal(json['maintenance_margin'])
34
34
  @daytrade_count = json['daytrade_count']
35
35
  @sma = json['sma']
36
36
  end
@@ -8,10 +8,10 @@ module Alpaca
8
8
 
9
9
  def initialize(json)
10
10
  @time = Time.at(json['t'])
11
- @open = json['o']
12
- @high = json['h']
13
- @low = json['l']
14
- @close = json['c']
11
+ @open = BigDecimal(json['o'], 2)
12
+ @high = BigDecimal(json['h'], 2)
13
+ @low = BigDecimal(json['l'], 2)
14
+ @close = BigDecimal(json['c'], 2)
15
15
  @volume = json['v']
16
16
  end
17
17
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alpaca
4
+ module Trade
5
+ module Api
6
+ class Calendar
7
+ attr_reader :date, :open, :close
8
+
9
+ def initialize(json)
10
+ @date = json['date']
11
+ @open = json['open']
12
+ @close = json['close']
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
3
4
  require 'faraday'
4
5
 
5
6
  module Alpaca
@@ -27,6 +28,12 @@ module Alpaca
27
28
  Asset.new(JSON.parse(response.body))
28
29
  end
29
30
 
31
+ def assets(status: nil, asset_class: nil)
32
+ response = get_request(endpoint, "v2/assets", { status: status, asset_class: asset_class }.compact)
33
+ json = JSON.parse(response.body)
34
+ json.map { |item| Asset.new(item) }
35
+ end
36
+
30
37
  def bars(timeframe, symbols)
31
38
  response = get_request(data_endpoint, "v1/bars/#{timeframe}", symbols: symbols.join(','))
32
39
  json = JSON.parse(response.body)
@@ -35,8 +42,85 @@ module Alpaca
35
42
  end
36
43
  end
37
44
 
45
+ def calendar(start_date: Date.today, end_date: (Date.today + 30))
46
+ params = { "start" => start_date.iso8601, "end" => end_date.iso8601 }
47
+ response = get_request(endpoint, "v2/calendar", params)
48
+ json = JSON.parse(response.body)
49
+ json.map { |item| Calendar.new(item) }
50
+ end
51
+
52
+ def cancel_order(id:)
53
+ response = delete_request(endpoint, "v2/orders/#{id}")
54
+ raise InvalidOrderId, JSON.parse(response.body)['message'] if response.status == 404
55
+ raise OrderNotCancelable if response.status == 422
56
+ end
57
+
58
+ def clock
59
+ response = get_request(endpoint, 'v2/clock')
60
+ Clock.new(JSON.parse(response.body))
61
+ end
62
+
63
+ def new_order(symbol:, qty:, side:, type:, time_in_force:, limit_price: nil,
64
+ stop_price: nil, extended_hours:, client_order_id: nil)
65
+
66
+ params = {
67
+ symbol: symbol,
68
+ qty: qty,
69
+ side: side,
70
+ type: type,
71
+ time_in_force: time_in_force,
72
+ limit_price: limit_price,
73
+ stop_price: stop_price,
74
+ extended_hours: extended_hours,
75
+ client_order_id: client_order_id
76
+ }
77
+ response = post_request(endpoint, 'v2/orders', params.compact)
78
+ raise InsufficientFunds, JSON.parse(response.body)['message'] if response.status == 403
79
+ raise MissingParameters, JSON.parse(response.body)['message'] if response.status == 422
80
+
81
+ Order.new(JSON.parse(response.body))
82
+ end
83
+
84
+ def order(id:)
85
+ response = get_request(endpoint, "v2/orders/#{id}")
86
+ raise InvalidOrderId, JSON.parse(response.body)['message'] if response.status == 404
87
+
88
+ Order.new(JSON.parse(response.body))
89
+ end
90
+
91
+ def orders(status: nil, after: nil, until_time: nil, direction: nil, limit: 50)
92
+ params = { status: status, after: after, until: until_time, direction: direction, limit: limit }
93
+ response = get_request(endpoint, "v2/orders", params.compact)
94
+ json = JSON.parse(response.body)
95
+ json.map { |item| Order.new(item) }
96
+ end
97
+
98
+ def position(symbol: nil)
99
+ response = get_request(endpoint, ["v2/positions", symbol].compact.join('/'))
100
+ raise NoPositionForSymbol, JSON.parse(response.body)['message'] if response.status == 404
101
+
102
+ Position.new(JSON.parse(response.body))
103
+ end
104
+
105
+ def positions(symbol: nil)
106
+ response = get_request(endpoint, ["v2/positions", symbol].compact.join('/'))
107
+ json = JSON.parse(response.body)
108
+ json.map { |item| Position.new(item) }
109
+ end
110
+
38
111
  private
39
112
 
113
+ def delete_request(endpoint, uri)
114
+ conn = Faraday.new(url: endpoint)
115
+ response = conn.delete(uri) do |req|
116
+ req.headers['APCA-API-KEY-ID'] = key_id
117
+ req.headers['APCA-API-SECRET-KEY'] = key_secret
118
+ end
119
+
120
+ possibly_raise_exception(response)
121
+ response
122
+ end
123
+
40
124
  def get_request(endpoint, uri, params = {})
41
125
  conn = Faraday.new(url: endpoint)
42
126
  response = conn.get(uri) do |req|
@@ -45,11 +129,33 @@ module Alpaca
45
129
  req.headers['APCA-API-SECRET-KEY'] = key_secret
46
130
  end
47
131
 
48
- raise UnauthorizedError, JSON.parse(response.body)['message'] if response.status == 401
49
- raise RateLimitedError, JSON.parse(response.body)['message'] if response.status == 429
132
+ possibly_raise_exception(response)
133
+ response
134
+ end
135
+
136
+ def post_request(endpoint, uri, params = {})
137
+ conn = Faraday.new(url: endpoint)
138
+ response = conn.post(uri) do |req|
139
+ req.body = params.to_json
140
+ req.headers['APCA-API-KEY-ID'] = key_id
141
+ req.headers['APCA-API-SECRET-KEY'] = key_secret
142
+ end
50
143
 
144
+ possibly_raise_exception(response)
51
145
  response
52
146
  end
147
+
148
+ def possibly_raise_exception(response)
149
+ if response.status == 401
150
+ raise UnauthorizedError, JSON.parse(response.body)['message']
151
+ end
152
+ if response.status == 429
153
+ raise RateLimitedError, JSON.parse(response.body)['message']
154
+ end
155
+ if response.status == 500
156
+ raise InternalServerError, JSON.parse(response.body)['message']
157
+ end
158
+ end
53
159
  end
54
160
  end
55
161
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alpaca
4
+ module Trade
5
+ module Api
6
+ class Clock
7
+ attr_reader :timestamp, :open, :next_open, :next_close
8
+
9
+ def initialize(json)
10
+ @timestamp = json['timestamp']
11
+ @open = json['open']
12
+ @next_open = json['next_open']
13
+ @next_close = json['next_close']
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -4,6 +4,12 @@ module Alpaca
4
4
  module Trade
5
5
  module Api
6
6
  class Error < StandardError; end
7
+ class InsufficientFunds < Error; end
8
+ class InternalServerError < Error; end
9
+ class InvalidOrderId < Error; end
10
+ class MissingParameters < Error; end
11
+ class NoPositionForSymbol < Error; end
12
+ class OrderNotCancelable < Error; end
7
13
  class RateLimitedError < Error; end
8
14
  class UnauthorizedError < Error; end
9
15
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alpaca
4
+ module Trade
5
+ module Api
6
+ class Order
7
+ attr_reader :id, :client_order_id, :created_at, :updated_at, :submitted_at,
8
+ :filled_at, :expired_at, :canceled_at, :failed_at, :asset_id, :symbol,
9
+ :asset_class, :qty, :filled_qty, :type, :side, :time_in_force, :limit_price,
10
+ :stop_price, :filled_avg_price, :status, :extended_hours
11
+
12
+ def initialize(json)
13
+ @id = json['id']
14
+ @client_order_id = json['client_order_id']
15
+ @created_at = json['created_at']
16
+ @updated_at = json['updated_at']
17
+ @submitted_at = json['submitted_at']
18
+ @filled_at = json['filled_at']
19
+ @expired_at = json['expired_at']
20
+ @canceled_at = json['canceled_at']
21
+ @failed_at = json['failed_at']
22
+ @asset_id = json['asset_id']
23
+ @symbol = json['symbol']
24
+ @asset_class = json['asset_class']
25
+ @qty = json['qty']
26
+ @filled_qty = json['filled_qty']
27
+ @type = json['type']
28
+ @side = json['side']
29
+ @time_in_force = json['time_in_force']
30
+ @limit_price = json['limit_price']
31
+ @stop_price = json['stop_price']
32
+ @filled_avg_price = json['filled_avg_price']
33
+ @status = json['status']
34
+ @extended_hours = json['extended_hours']
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alpaca
4
+ module Trade
5
+ module Api
6
+ class Position
7
+ attr_reader :asset_id, :symbol, :exchange, :asset_class, :avg_entry_price,
8
+ :qty, :side, :market_value, :cost_basis, :unrealized_pl, :unrealized_plpc,
9
+ :unrealized_intraday_pl, :unrealized_intraday_plpc, :current_price,
10
+ :lastday_price, :change_today
11
+
12
+ def initialize(json)
13
+ @asset_id = json['asset_id']
14
+ @symbol = json['symbol']
15
+ @exchange = json['exchange']
16
+ @asset_class = json['asset_class']
17
+ @avg_entry_price = json['avg_entry_price']
18
+ @qty = json['qty']
19
+ @side = json['side']
20
+ @market_value = json['market_value']
21
+ @cost_basis = json['cost_basis']
22
+ @unrealized_pl = json['unrealized_pl']
23
+ @unrealized_plpc = json['unrealized_plpc']
24
+ @unrealized_intraday_pl = json['unrealized_intraday_pl']
25
+ @unrealized_intraday_plpc = json['unrealized_intraday_plpc']
26
+ @current_price = json['current_price']
27
+ @lastday_price = json['lastday_price']
28
+ @change_today = json['change_today']
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -3,7 +3,7 @@
3
3
  module Alpaca
4
4
  module Trade
5
5
  module Api
6
- VERSION = '0.1.0'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alpaca-trade-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cloves Carneiro Jr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-05 00:00:00.000000000 Z
11
+ date: 2019-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -160,9 +160,13 @@ files:
160
160
  - lib/alpaca/trade/api/account.rb
161
161
  - lib/alpaca/trade/api/asset.rb
162
162
  - lib/alpaca/trade/api/bar.rb
163
+ - lib/alpaca/trade/api/calendar.rb
163
164
  - lib/alpaca/trade/api/client.rb
165
+ - lib/alpaca/trade/api/clock.rb
164
166
  - lib/alpaca/trade/api/configuration.rb
165
167
  - lib/alpaca/trade/api/errors.rb
168
+ - lib/alpaca/trade/api/order.rb
169
+ - lib/alpaca/trade/api/position.rb
166
170
  - lib/alpaca/trade/api/version.rb
167
171
  homepage: https://github.com/ccjr/alpaca-trade-api
168
172
  licenses: