alpaca-trade-api 0.1.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +30 -1
- data/Gemfile.lock +5 -5
- data/README.md +38 -7
- data/alpaca-trade-api.gemspec +1 -1
- data/lib/alpaca/trade/api.rb +7 -0
- data/lib/alpaca/trade/api/account.rb +9 -9
- data/lib/alpaca/trade/api/bar.rb +4 -4
- data/lib/alpaca/trade/api/calendar.rb +17 -0
- data/lib/alpaca/trade/api/client.rb +194 -4
- data/lib/alpaca/trade/api/clock.rb +18 -0
- data/lib/alpaca/trade/api/errors.rb +7 -0
- data/lib/alpaca/trade/api/last_trade.rb +15 -0
- data/lib/alpaca/trade/api/order.rb +46 -0
- data/lib/alpaca/trade/api/position.rb +33 -0
- data/lib/alpaca/trade/api/version.rb +1 -1
- metadata +9 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 7e5e11fb99efb22e866a8f2cba25f51c4461243a1e29c6a27bca7e37f6d90ab6
         | 
| 4 | 
            +
              data.tar.gz: bf33b4ac115ec3db6d12f1f9e8463dccd0c33bef5eeba88625ee3e0ca8583f42
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: c6c4b7f0efdd86c0930db2e7c4cda494faab106722afa5d4187b242750e9885f2ae8845af1ca947200be2432869f0503fc9a11bff47dde20762259b5aa44bf00
         | 
| 7 | 
            +
              data.tar.gz: 9a9900150e64e4c9e7366578edf42fcb803c08f97a622737f55678e00227f309ae6a8718cf76fe4e7e7f5b340bbb8d914308f2bfbdcf55dfea3fae74c72e7437
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.6. | 
| 1 | 
            +
            2.6.4
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -4,7 +4,36 @@ 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 | 
            -
            ## [ | 
| 7 | 
            +
            ## [0.5.0] - 2020-05-25
         | 
| 8 | 
            +
            ### Added
         | 
| 9 | 
            +
            - Implemented Client#last_trade. Thanks @nathanworden.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## [0.4.1] - 2020-04-25
         | 
| 12 | 
            +
            ### Fixed
         | 
| 13 | 
            +
            - Added explicit `BigDecimal` require.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## [0.4.0] - 2020-02-16
         | 
| 16 | 
            +
            ### Added
         | 
| 17 | 
            +
            - Supporting [Bracket Orders](https://docs.alpaca.markets/trading-on-alpaca/orders/#bracket-orders)
         | 
| 18 | 
            +
            - Validating time frame in Client#bars
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## [0.3.0] - 2019-09-19
         | 
| 21 | 
            +
            ### Added
         | 
| 22 | 
            +
            - Implemented new endpoints:
         | 
| 23 | 
            +
              * Client#cancel_orders
         | 
| 24 | 
            +
              * Client#close_position
         | 
| 25 | 
            +
              * Client#close_positions
         | 
| 26 | 
            +
              * Client#replace_order
         | 
| 27 | 
            +
            - Added limit as a parameter to Client#bars
         | 
| 28 | 
            +
            - Renamed Clock#open to Clock#is_open and fixed assignment.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            ## [0.2.0] - 2019-07-10
         | 
| 31 | 
            +
            ### Added
         | 
| 32 | 
            +
            - Implemented Client#calendar.
         | 
| 33 | 
            +
            - Implemented Client#clock.
         | 
| 34 | 
            +
            - Added Client#assets.
         | 
| 35 | 
            +
            - Implemented new methods in Client: new_order, order, orders, position, positions.
         | 
| 36 | 
            +
            - Implemented Client#cancel_order.
         | 
| 8 37 |  | 
| 9 38 | 
             
            ## [0.1.0] - 2019-07-04
         | 
| 10 39 | 
             
            ### Added
         | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                alpaca-trade-api (0. | 
| 4 | 
            +
                alpaca-trade-api (0.5.0)
         | 
| 5 5 | 
             
                  faraday (~> 0.15)
         | 
| 6 6 |  | 
| 7 7 | 
             
            GEM
         | 
| @@ -14,13 +14,13 @@ GEM | |
| 14 14 | 
             
                  safe_yaml (~> 1.0.0)
         | 
| 15 15 | 
             
                diff-lcs (1.3)
         | 
| 16 16 | 
             
                docile (1.3.2)
         | 
| 17 | 
            -
                faraday (0. | 
| 17 | 
            +
                faraday (0.17.3)
         | 
| 18 18 | 
             
                  multipart-post (>= 1.2, < 3)
         | 
| 19 19 | 
             
                hashdiff (0.4.0)
         | 
| 20 20 | 
             
                json (2.2.0)
         | 
| 21 21 | 
             
                multipart-post (2.1.1)
         | 
| 22 22 | 
             
                public_suffix (3.1.1)
         | 
| 23 | 
            -
                rake ( | 
| 23 | 
            +
                rake (13.0.1)
         | 
| 24 24 | 
             
                rb-readline (0.5.5)
         | 
| 25 25 | 
             
                rspec (3.8.0)
         | 
| 26 26 | 
             
                  rspec-core (~> 3.8.0)
         | 
| @@ -54,7 +54,7 @@ DEPENDENCIES | |
| 54 54 | 
             
              alpaca-trade-api!
         | 
| 55 55 | 
             
              bundler (~> 2.0)
         | 
| 56 56 | 
             
              byebug
         | 
| 57 | 
            -
              rake (~>  | 
| 57 | 
            +
              rake (~> 13.0)
         | 
| 58 58 | 
             
              rb-readline
         | 
| 59 59 | 
             
              rspec (~> 3.0)
         | 
| 60 60 | 
             
              simplecov (~> 0.16)
         | 
| @@ -62,4 +62,4 @@ DEPENDENCIES | |
| 62 62 | 
             
              webmock (~> 3.0)
         | 
| 63 63 |  | 
| 64 64 | 
             
            BUNDLED WITH
         | 
| 65 | 
            -
               2.0. | 
| 65 | 
            +
               2.0.2
         | 
    
        data/README.md
    CHANGED
    
    | @@ -26,23 +26,54 @@ By default, the library is configured to use the Paper Trading host - `https://p | |
| 26 26 |  | 
| 27 27 | 
             
            ```ruby
         | 
| 28 28 | 
             
            Alpaca::Trade::Api.configure do |config|
         | 
| 29 | 
            -
              config.endpoint = 'https://api. | 
| 29 | 
            +
              config.endpoint = 'https://api.alpaca.markets'
         | 
| 30 30 | 
             
              config.key_id = 'A_KEY_ID'
         | 
| 31 31 | 
             
              config.key_secret = 'A_S3CRET'
         | 
| 32 32 | 
             
            end
         | 
| 33 33 | 
             
            ```
         | 
| 34 34 |  | 
| 35 | 
            -
            ### Account
         | 
| 36 35 |  | 
| 37 | 
            -
             | 
| 36 | 
            +
            ### Example
         | 
| 38 37 |  | 
| 39 | 
            -
             | 
| 38 | 
            +
            Here's an example on how to use the library to read details of an account's orders in paper trading.
         | 
| 40 39 |  | 
| 41 | 
            -
             | 
| 40 | 
            +
            ```ruby
         | 
| 41 | 
            +
            require 'alpaca/trade/api'
         | 
| 42 42 |  | 
| 43 | 
            -
             | 
| 43 | 
            +
            Alpaca::Trade::Api.configure do |config|
         | 
| 44 | 
            +
              config.endpoint = 'https://paper-api.alpaca.markets'
         | 
| 45 | 
            +
              config.key_id = 'xxxxxxxx'
         | 
| 46 | 
            +
              config.key_secret = 'xxxxx'
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            client =  Alpaca::Trade::Api::Client.new
         | 
| 50 | 
            +
            puts client.orders.last.inspect
         | 
| 51 | 
            +
            ```
         | 
| 44 52 |  | 
| 45 | 
            -
             | 
| 53 | 
            +
            ### Supported endpoints
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            Here's a table with all currently supported endpoints in this library:
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            | Object | Action | Method |
         | 
| 58 | 
            +
            |------------------------------------------------------------------------------|---------------------------------------|--------------------------------|
         | 
| 59 | 
            +
            | [Account](https://docs.alpaca.markets/api-documentation/api-v2/account/)     | [GET] Get the account                 | Client#account                 |
         | 
| 60 | 
            +
            | [Orders](https://docs.alpaca.markets/api-documentation/api-v2/orders/)       | [GET] Get a list of orders            | Client#orders                  |
         | 
| 61 | 
            +
            |                                                                              | [POST] Request a new order            | Client#new_order               |
         | 
| 62 | 
            +
            |                                                                              | [GET] Get an order                    | Client#order(id:)              |
         | 
| 63 | 
            +
            |                                                                              | [GET] Get an order by client order id | Client#order(id:)              |
         | 
| 64 | 
            +
            |                                                                              | [PATCH] Replace an order              | Client#replace_order           |
         | 
| 65 | 
            +
            |                                                                              | [DELETE] Cancel all orders            | Client#cancel_orders           |
         | 
| 66 | 
            +
            |                                                                              | [DELETE] Cancel an order              | Client#cancel_order(id:)       |
         | 
| 67 | 
            +
            | [Positions](https://docs.alpaca.markets/api-documentation/api-v2/positions/) | [GET] Get open positions              | Client#positions               |
         | 
| 68 | 
            +
            |                                                                              | [GET] Get an open position            | Client#position(symbol:)       |
         | 
| 69 | 
            +
            |                                                                              | [DELETE] Close all positions          | Client#close_positions         |
         | 
| 70 | 
            +
            |                                                                              | [DELETE] Close a position             | Client#close_position(symbol:) |
         | 
| 71 | 
            +
            | [Assets](https://docs.alpaca.markets/api-documentation/api-v2/assets/)       | [GET] Get assets                      | Client#assets                  |
         | 
| 72 | 
            +
            |                                                                              | [GET] Get assets/:id                  | Client#asset(symbol:)          |
         | 
| 73 | 
            +
            |                                                                              | [GET] Get an asset                    | Client#asset(symbol:)          |
         | 
| 74 | 
            +
            | [Calendar](https://docs.alpaca.markets/api-documentation/api-v2/calendar/)   | [GET] Get the calendar                | Client#calendar(start_date:, end_date:) |
         | 
| 75 | 
            +
            | [Clock](https://docs.alpaca.markets/api-documentation/api-v2/clock/)         | [GET] Get the clock                   | Client#clock                            |
         | 
| 76 | 
            +
            | [Bars](https://docs.alpaca.markets/api-documentation/api-v2/market-data/bars/) | [GET] Get a list of bars            | Client#bars(timeframe, symbols, limit:) |
         | 
| 46 77 |  | 
| 47 78 | 
             
            ## Development
         | 
| 48 79 |  | 
    
        data/alpaca-trade-api.gemspec
    CHANGED
    
    | @@ -39,7 +39,7 @@ Gem::Specification.new do |spec| | |
| 39 39 | 
             
              spec.add_development_dependency "bundler", "~> 2.0"
         | 
| 40 40 | 
             
              spec.add_development_dependency "byebug"
         | 
| 41 41 | 
             
              spec.add_development_dependency 'rb-readline'
         | 
| 42 | 
            -
              spec.add_development_dependency "rake", "~>  | 
| 42 | 
            +
              spec.add_development_dependency "rake", "~> 13.0"
         | 
| 43 43 | 
             
              spec.add_development_dependency "rspec", "~> 3.0"
         | 
| 44 44 | 
             
              spec.add_development_dependency "simplecov", "~> 0.16"
         | 
| 45 45 | 
             
              spec.add_development_dependency "vcr", "~> 5.0"
         | 
    
        data/lib/alpaca/trade/api.rb
    CHANGED
    
    | @@ -6,9 +6,16 @@ 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/last_trade'
         | 
| 12 | 
            +
            require 'alpaca/trade/api/order'
         | 
| 13 | 
            +
            require 'alpaca/trade/api/position'
         | 
| 14 | 
            +
             | 
| 9 15 | 
             
            require 'alpaca/trade/api/client'
         | 
| 10 16 | 
             
            require 'alpaca/trade/api/errors'
         | 
| 11 17 |  | 
| 18 | 
            +
            require 'bigdecimal/util'
         | 
| 12 19 | 
             
            require 'json'
         | 
| 13 20 |  | 
| 14 21 | 
             
            module Alpaca
         | 
| @@ -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
         | 
    
        data/lib/alpaca/trade/api/bar.rb
    CHANGED
    
    | @@ -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'].to_s)
         | 
| 12 | 
            +
                      @high = BigDecimal(json['h'].to_s)
         | 
| 13 | 
            +
                      @low = BigDecimal(json['l'].to_s)
         | 
| 14 | 
            +
                      @close = BigDecimal(json['c'].to_s)
         | 
| 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
         | 
| @@ -8,6 +9,8 @@ module Alpaca | |
| 8 9 | 
             
                  class Client
         | 
| 9 10 | 
             
                    attr_reader :data_endpoint, :endpoint, :key_id, :key_secret
         | 
| 10 11 |  | 
| 12 | 
            +
                    TIMEFRAMES = ['minute', '1Min', '5Min', '15Min', 'day', '1D']
         | 
| 13 | 
            +
             | 
| 11 14 | 
             
                    def initialize(endpoint: Alpaca::Trade::Api.configuration.endpoint,
         | 
| 12 15 | 
             
                                   key_id: Alpaca::Trade::Api.configuration.key_id,
         | 
| 13 16 | 
             
                                   key_secret: Alpaca::Trade::Api.configuration.key_secret)
         | 
| @@ -27,16 +30,163 @@ module Alpaca | |
| 27 30 | 
             
                      Asset.new(JSON.parse(response.body))
         | 
| 28 31 | 
             
                    end
         | 
| 29 32 |  | 
| 30 | 
            -
                    def  | 
| 31 | 
            -
                      response = get_request( | 
| 33 | 
            +
                    def assets(status: nil, asset_class: nil)
         | 
| 34 | 
            +
                      response = get_request(endpoint, "v2/assets", { status: status, asset_class: asset_class }.compact)
         | 
| 35 | 
            +
                      json = JSON.parse(response.body)
         | 
| 36 | 
            +
                      json.map { |item| Asset.new(item) }
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    def bars(timeframe, symbols, limit: 100)
         | 
| 40 | 
            +
                      validate_timeframe(timeframe)
         | 
| 41 | 
            +
                      response = get_request(data_endpoint, "v1/bars/#{timeframe}", symbols: symbols.join(','), limit: limit)
         | 
| 32 42 | 
             
                      json = JSON.parse(response.body)
         | 
| 33 43 | 
             
                      json.keys.each_with_object({}) do |symbol, hash|
         | 
| 34 44 | 
             
                        hash[symbol] = json[symbol].map { |bar| Bar.new(bar) }
         | 
| 35 45 | 
             
                      end
         | 
| 36 46 | 
             
                    end
         | 
| 37 47 |  | 
| 48 | 
            +
                    def calendar(start_date: Date.today, end_date: (Date.today + 30))
         | 
| 49 | 
            +
                      # FIX, use start_date.strftime('%F')
         | 
| 50 | 
            +
                      params = { "start" => start_date.iso8601, "end" => end_date.iso8601 }
         | 
| 51 | 
            +
                      response = get_request(endpoint, "v2/calendar", params)
         | 
| 52 | 
            +
                      json = JSON.parse(response.body)
         | 
| 53 | 
            +
                      json.map { |item| Calendar.new(item) }
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def cancel_order(id:)
         | 
| 57 | 
            +
                      response = delete_request(endpoint, "v2/orders/#{id}")
         | 
| 58 | 
            +
                      raise InvalidOrderId, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 59 | 
            +
                      raise OrderNotCancelable if response.status == 422
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    def cancel_orders
         | 
| 63 | 
            +
                      response = delete_request(endpoint, 'v2/orders')
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      json = JSON.parse(response.body)
         | 
| 66 | 
            +
                      json.map do |item|
         | 
| 67 | 
            +
                        {
         | 
| 68 | 
            +
                          'id' => item['id'],
         | 
| 69 | 
            +
                          'status' => item['status'],
         | 
| 70 | 
            +
                          'body' => Order.new(item['body']),
         | 
| 71 | 
            +
                        }
         | 
| 72 | 
            +
                      end
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    def clock
         | 
| 76 | 
            +
                      response = get_request(endpoint, 'v2/clock')
         | 
| 77 | 
            +
                      Clock.new(JSON.parse(response.body))
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    def close_position(symbol:)
         | 
| 81 | 
            +
                      response = delete_request(endpoint, "v2/positions/#{symbol}")
         | 
| 82 | 
            +
                      raise NoPositionForSymbol, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                      Position.new(JSON.parse(response.body))
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    def close_positions
         | 
| 88 | 
            +
                      response = delete_request(endpoint, 'v2/positions')
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                      json = JSON.parse(response.body)
         | 
| 91 | 
            +
                      json.map do |item|
         | 
| 92 | 
            +
                        {
         | 
| 93 | 
            +
                          'symbol' => item['symbol'],
         | 
| 94 | 
            +
                          'status' => item['status'],
         | 
| 95 | 
            +
                          'body' => Position.new(item['body']),
         | 
| 96 | 
            +
                        }
         | 
| 97 | 
            +
                      end
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    def last_trade(symbol:)
         | 
| 101 | 
            +
                      response = get_request(data_endpoint, "v1/last/stocks/#{symbol}")
         | 
| 102 | 
            +
                      raise InvalidRequest, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                      LastTrade.new(JSON.parse(response.body))
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    def new_order(symbol:, qty:, side:, type:, time_in_force:, limit_price: nil,
         | 
| 108 | 
            +
                      stop_price: nil, extended_hours: false, client_order_id: nil, order_class: nil,
         | 
| 109 | 
            +
                      take_profit: nil, stop_loss: nil)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                      params = {
         | 
| 112 | 
            +
                        symbol: symbol,
         | 
| 113 | 
            +
                        qty: qty,
         | 
| 114 | 
            +
                        side: side,
         | 
| 115 | 
            +
                        type: type,
         | 
| 116 | 
            +
                        time_in_force: time_in_force,
         | 
| 117 | 
            +
                        limit_price: limit_price,
         | 
| 118 | 
            +
                        order_class: order_class,
         | 
| 119 | 
            +
                        stop_price: stop_price,
         | 
| 120 | 
            +
                        take_profit: take_profit,
         | 
| 121 | 
            +
                        stop_loss: stop_loss,
         | 
| 122 | 
            +
                        extended_hours: extended_hours,
         | 
| 123 | 
            +
                        client_order_id: client_order_id
         | 
| 124 | 
            +
                      }
         | 
| 125 | 
            +
                      response = post_request(endpoint, 'v2/orders', params.compact)
         | 
| 126 | 
            +
                      raise InsufficientFunds, JSON.parse(response.body)['message'] if response.status == 403
         | 
| 127 | 
            +
                      raise MissingParameters, JSON.parse(response.body)['message'] if response.status == 422
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                      Order.new(JSON.parse(response.body))
         | 
| 130 | 
            +
                    end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                    def order(id:)
         | 
| 133 | 
            +
                      response = get_request(endpoint, "v2/orders/#{id}")
         | 
| 134 | 
            +
                      raise InvalidOrderId, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                      Order.new(JSON.parse(response.body))
         | 
| 137 | 
            +
                    end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    def orders(status: nil, after: nil, until_time: nil, direction: nil, limit: 50)
         | 
| 140 | 
            +
                      params = { status: status, after: after, until: until_time, direction: direction, limit: limit }
         | 
| 141 | 
            +
                      response = get_request(endpoint, "v2/orders", params.compact)
         | 
| 142 | 
            +
                      json = JSON.parse(response.body)
         | 
| 143 | 
            +
                      json.map { |item| Order.new(item) }
         | 
| 144 | 
            +
                    end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    def position(symbol: nil)
         | 
| 147 | 
            +
                      response = get_request(endpoint, ["v2/positions", symbol].compact.join('/'))
         | 
| 148 | 
            +
                      raise NoPositionForSymbol, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                      Position.new(JSON.parse(response.body))
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                    def positions(symbol: nil)
         | 
| 154 | 
            +
                      response = get_request(endpoint, ["v2/positions", symbol].compact.join('/'))
         | 
| 155 | 
            +
                      json = JSON.parse(response.body)
         | 
| 156 | 
            +
                      json.map { |item| Position.new(item) }
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                    def replace_order(id:, qty: nil, time_in_force: nil, limit_price: nil,
         | 
| 160 | 
            +
                                      stop_price: nil, client_order_id: nil)
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                      params = {
         | 
| 163 | 
            +
                        qty: qty,
         | 
| 164 | 
            +
                        time_in_force: time_in_force,
         | 
| 165 | 
            +
                        limit_price: limit_price,
         | 
| 166 | 
            +
                        stop_price: stop_price,
         | 
| 167 | 
            +
                        client_order_id: client_order_id
         | 
| 168 | 
            +
                      }
         | 
| 169 | 
            +
                      response = patch_request(endpoint, "v2/orders/#{id}", params.compact)
         | 
| 170 | 
            +
                      raise InsufficientFunds, JSON.parse(response.body)['message'] if response.status == 403
         | 
| 171 | 
            +
                      raise InvalidOrderId, JSON.parse(response.body)['message'] if response.status == 404
         | 
| 172 | 
            +
                      raise InvalidRequest, JSON.parse(response.body)['message'] if response.status == 422
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                      Order.new(JSON.parse(response.body))
         | 
| 175 | 
            +
                    end
         | 
| 176 | 
            +
             | 
| 38 177 | 
             
                    private
         | 
| 39 178 |  | 
| 179 | 
            +
                    def delete_request(endpoint, uri)
         | 
| 180 | 
            +
                      conn = Faraday.new(url: endpoint)
         | 
| 181 | 
            +
                      response = conn.delete(uri) do |req|
         | 
| 182 | 
            +
                        req.headers['APCA-API-KEY-ID'] = key_id
         | 
| 183 | 
            +
                        req.headers['APCA-API-SECRET-KEY'] = key_secret
         | 
| 184 | 
            +
                      end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                      possibly_raise_exception(response)
         | 
| 187 | 
            +
                      response
         | 
| 188 | 
            +
                    end
         | 
| 189 | 
            +
             | 
| 40 190 | 
             
                    def get_request(endpoint, uri, params = {})
         | 
| 41 191 | 
             
                      conn = Faraday.new(url: endpoint)
         | 
| 42 192 | 
             
                      response = conn.get(uri) do |req|
         | 
| @@ -45,11 +195,51 @@ module Alpaca | |
| 45 195 | 
             
                        req.headers['APCA-API-SECRET-KEY'] = key_secret
         | 
| 46 196 | 
             
                      end
         | 
| 47 197 |  | 
| 48 | 
            -
                       | 
| 49 | 
            -
                       | 
| 198 | 
            +
                      possibly_raise_exception(response)
         | 
| 199 | 
            +
                      response
         | 
| 200 | 
            +
                    end
         | 
| 50 201 |  | 
| 202 | 
            +
                    def patch_request(endpoint, uri, params = {})
         | 
| 203 | 
            +
                      conn = Faraday.new(url: endpoint)
         | 
| 204 | 
            +
                      response = conn.patch(uri) do |req|
         | 
| 205 | 
            +
                        req.body = params.to_json
         | 
| 206 | 
            +
                        req.headers['APCA-API-KEY-ID'] = key_id
         | 
| 207 | 
            +
                        req.headers['APCA-API-SECRET-KEY'] = key_secret
         | 
| 208 | 
            +
                      end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                      possibly_raise_exception(response)
         | 
| 51 211 | 
             
                      response
         | 
| 52 212 | 
             
                    end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                    def post_request(endpoint, uri, params = {})
         | 
| 215 | 
            +
                      conn = Faraday.new(url: endpoint)
         | 
| 216 | 
            +
                      response = conn.post(uri) do |req|
         | 
| 217 | 
            +
                        req.body = params.to_json
         | 
| 218 | 
            +
                        req.headers['APCA-API-KEY-ID'] = key_id
         | 
| 219 | 
            +
                        req.headers['APCA-API-SECRET-KEY'] = key_secret
         | 
| 220 | 
            +
                      end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                      possibly_raise_exception(response)
         | 
| 223 | 
            +
                      response
         | 
| 224 | 
            +
                    end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                    def possibly_raise_exception(response)
         | 
| 227 | 
            +
                      if response.status == 401
         | 
| 228 | 
            +
                        raise UnauthorizedError, JSON.parse(response.body)['message']
         | 
| 229 | 
            +
                      end
         | 
| 230 | 
            +
                      if response.status == 429
         | 
| 231 | 
            +
                        raise RateLimitedError, JSON.parse(response.body)['message']
         | 
| 232 | 
            +
                      end
         | 
| 233 | 
            +
                      if response.status == 500
         | 
| 234 | 
            +
                        raise InternalServerError, JSON.parse(response.body)['message']
         | 
| 235 | 
            +
                      end
         | 
| 236 | 
            +
                    end
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                    def validate_timeframe(timeframe)
         | 
| 239 | 
            +
                      unless TIMEFRAMES.include?(timeframe)
         | 
| 240 | 
            +
                        raise ArgumentError, "Invalid timeframe: #{timeframe}. Valid arguments are: #{TIMEFRAMES}"
         | 
| 241 | 
            +
                      end
         | 
| 242 | 
            +
                    end
         | 
| 53 243 | 
             
                  end
         | 
| 54 244 | 
             
                end
         | 
| 55 245 | 
             
              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, :is_open, :next_open, :next_close
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def initialize(json)
         | 
| 10 | 
            +
                      @timestamp = json['timestamp']
         | 
| 11 | 
            +
                      @is_open = json['is_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,13 @@ 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 InvalidRequest < Error; end
         | 
| 11 | 
            +
                  class MissingParameters < Error; end
         | 
| 12 | 
            +
                  class NoPositionForSymbol < Error; end
         | 
| 13 | 
            +
                  class OrderNotCancelable < Error; end
         | 
| 7 14 | 
             
                  class RateLimitedError < Error; end
         | 
| 8 15 | 
             
                  class UnauthorizedError < Error; end
         | 
| 9 16 | 
             
                end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Alpaca
         | 
| 4 | 
            +
              module Trade
         | 
| 5 | 
            +
                module Api
         | 
| 6 | 
            +
                  class Order
         | 
| 7 | 
            +
                    attr_reader :id, :asset_class, :asset_id, :canceled_at, :client_order_id,
         | 
| 8 | 
            +
                      :created_at, :expired_at, :extended_hours, :failed_at, :filled_at, :filled_avg_price,
         | 
| 9 | 
            +
                      :filled_qty, :legs, :limit_price, :order_class, :qty, :replaced_at, :replaced_by,
         | 
| 10 | 
            +
                      :replaces, :side, :status, :stop_price, :submitted_at, :symbol, :time_in_force,
         | 
| 11 | 
            +
                      :type, :updated_at
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def initialize(json)
         | 
| 14 | 
            +
                      @id = json['id']
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                      @asset_class = json['asset_class']
         | 
| 17 | 
            +
                      @asset_id = json['asset_id']
         | 
| 18 | 
            +
                      @canceled_at = json['canceled_at']
         | 
| 19 | 
            +
                      @client_order_id = json['client_order_id']
         | 
| 20 | 
            +
                      @created_at = json['created_at']
         | 
| 21 | 
            +
                      @expired_at = json['expired_at']
         | 
| 22 | 
            +
                      @extended_hours = json['extended_hours']
         | 
| 23 | 
            +
                      @failed_at = json['failed_at']
         | 
| 24 | 
            +
                      @filled_at = json['filled_at']
         | 
| 25 | 
            +
                      @filled_avg_price = json['filled_avg_price']
         | 
| 26 | 
            +
                      @filled_qty = json['filled_qty']
         | 
| 27 | 
            +
                      @legs = (json['legs'] || []).map {|leg| Order.new(leg)}
         | 
| 28 | 
            +
                      @limit_price = json['limit_price']
         | 
| 29 | 
            +
                      @order_class = json['order_class']
         | 
| 30 | 
            +
                      @qty = json['qty']
         | 
| 31 | 
            +
                      @replaced_at = json['replaced_at']
         | 
| 32 | 
            +
                      @replaced_by = json['replaced_by']
         | 
| 33 | 
            +
                      @replaces = json['replaces']
         | 
| 34 | 
            +
                      @side = json['side']
         | 
| 35 | 
            +
                      @status = json['status']
         | 
| 36 | 
            +
                      @stop_price = json['stop_price']
         | 
| 37 | 
            +
                      @submitted_at = json['submitted_at']
         | 
| 38 | 
            +
                      @symbol = json['symbol']
         | 
| 39 | 
            +
                      @time_in_force = json['time_in_force']
         | 
| 40 | 
            +
                      @type = json['type']
         | 
| 41 | 
            +
                      @updated_at = json['updated_at']
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            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
         | 
    
        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. | 
| 4 | 
            +
              version: 0.5.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:  | 
| 11 | 
            +
            date: 2020-05-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -58,14 +58,14 @@ dependencies: | |
| 58 58 | 
             
                requirements:
         | 
| 59 59 | 
             
                - - "~>"
         | 
| 60 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            -
                    version: ' | 
| 61 | 
            +
                    version: '13.0'
         | 
| 62 62 | 
             
              type: :development
         | 
| 63 63 | 
             
              prerelease: false
         | 
| 64 64 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 65 | 
             
                requirements:
         | 
| 66 66 | 
             
                - - "~>"
         | 
| 67 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            -
                    version: ' | 
| 68 | 
            +
                    version: '13.0'
         | 
| 69 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 70 | 
             
              name: rspec
         | 
| 71 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -160,9 +160,14 @@ 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/last_trade.rb
         | 
| 169 | 
            +
            - lib/alpaca/trade/api/order.rb
         | 
| 170 | 
            +
            - lib/alpaca/trade/api/position.rb
         | 
| 166 171 | 
             
            - lib/alpaca/trade/api/version.rb
         | 
| 167 172 | 
             
            homepage: https://github.com/ccjr/alpaca-trade-api
         | 
| 168 173 | 
             
            licenses:
         |