kalshi 0.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.
- checksums.yaml +7 -0
- data/.release-please-config.json +28 -0
- data/.release-please-manifest.json +3 -0
- data/CHANGELOG.md +46 -0
- data/Rakefile +16 -0
- data/Readme.adoc +231 -0
- data/ci/build_image.sh +248 -0
- data/ci/publish-gem.sh +91 -0
- data/lib/kalshi/api_client.rb +48 -0
- data/lib/kalshi/client.rb +85 -0
- data/lib/kalshi/contract.rb +34 -0
- data/lib/kalshi/endpoint.rb +32 -0
- data/lib/kalshi/events/client.rb +30 -0
- data/lib/kalshi/events/list.rb +37 -0
- data/lib/kalshi/events/multivariate.rb +28 -0
- data/lib/kalshi/listable.rb +31 -0
- data/lib/kalshi/market/client.rb +40 -0
- data/lib/kalshi/market/markets.rb +36 -0
- data/lib/kalshi/market/orderbook.rb +16 -0
- data/lib/kalshi/market/series.rb +14 -0
- data/lib/kalshi/market/series_list.rb +29 -0
- data/lib/kalshi/market/trades.rb +29 -0
- data/lib/kalshi/operations/.gitkeep +0 -0
- data/lib/kalshi/search/client.rb +18 -0
- data/lib/kalshi/search/series_tags.rb +14 -0
- data/lib/kalshi/search/sports_filters.rb +14 -0
- data/lib/kalshi/series/client.rb +18 -0
- data/lib/kalshi/series/event_candlesticks.rb +34 -0
- data/lib/kalshi/series/forecast_percentile_history.rb +36 -0
- data/lib/kalshi/series/market_candlesticks.rb +28 -0
- data/lib/kalshi/version.rb +10 -0
- data/lib/kalshi.rb +35 -0
- data/sig/kalshi/rb.rbs +6 -0
- metadata +214 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
# Base class for API client wrappers that automatically configure URL prefixes
|
|
6
|
+
#
|
|
7
|
+
# @example Using ApiClient with a Search namespace
|
|
8
|
+
# # For Rubyists::Kalshi::Search::Client, the prefix will be "search"
|
|
9
|
+
# class Search::Client < ApiClient
|
|
10
|
+
# # API calls will automatically use /search/ prefix
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# @example Overriding the automatic prefix
|
|
14
|
+
# class CustomClient < ApiClient
|
|
15
|
+
# self.prefix = 'custom_api'
|
|
16
|
+
# end
|
|
17
|
+
class ApiClient
|
|
18
|
+
attr_reader :client
|
|
19
|
+
|
|
20
|
+
# Automatically extract the URL prefix from the module hierarchy
|
|
21
|
+
#
|
|
22
|
+
# The prefix is derived by taking the second-to-last component of the
|
|
23
|
+
# fully qualified class name and converting it to lowercase. For example:
|
|
24
|
+
# - Rubyists::Kalshi::Search::Client => "search"
|
|
25
|
+
# - Rubyists::Kalshi::Market::Client => "market"
|
|
26
|
+
#
|
|
27
|
+
# @return [String] the URL prefix for API calls
|
|
28
|
+
def self.prefix
|
|
29
|
+
@prefix ||= to_s.split('::')[-2].downcase
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Set a custom URL prefix for API calls, for overriding the default behavior
|
|
33
|
+
def self.prefix=(value) # rubocop:disable Style/TrivialAccessors
|
|
34
|
+
@prefix = value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Initialize the ApiClient with a given client instance
|
|
38
|
+
#
|
|
39
|
+
# @param client [Rubyists::Kalshi::Client] the client instance to wrap
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
def initialize(client)
|
|
43
|
+
@client = client
|
|
44
|
+
client.prefix = self.class.prefix
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'httpx'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'uri'
|
|
6
|
+
|
|
7
|
+
module Rubyists
|
|
8
|
+
module Kalshi
|
|
9
|
+
# HTTP Client for Kalshi API
|
|
10
|
+
class Client
|
|
11
|
+
include SemanticLogger::Loggable
|
|
12
|
+
|
|
13
|
+
attr_reader :http, :base_url
|
|
14
|
+
attr_accessor :prefix
|
|
15
|
+
|
|
16
|
+
def initialize(base_url: Kalshi.config.base_url)
|
|
17
|
+
@base_url = base_url
|
|
18
|
+
@http = HTTPX.plugin(:persistent)
|
|
19
|
+
.plugin(:rate_limiter)
|
|
20
|
+
.with(origin: base_url)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Get response from a path, adding the base_url,
|
|
24
|
+
# and a prefix, if set on the client.
|
|
25
|
+
#
|
|
26
|
+
# see #full_path for details
|
|
27
|
+
#
|
|
28
|
+
# @param path [String] The URL path
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash] The parsed JSON response
|
|
31
|
+
def get(path, params: {})
|
|
32
|
+
get_url(full_url(path), params:)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get response from a URL
|
|
36
|
+
# Must pass a full URL, including scheme (http/https), host, etc.
|
|
37
|
+
#
|
|
38
|
+
# @param path [String] The full URL path
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash] The parsed JSON response
|
|
41
|
+
def get_url(url, params: {})
|
|
42
|
+
uri = URI.parse(url)
|
|
43
|
+
raise ArgumentError, 'URL must be http or https' unless %w[http https].include?(uri.scheme)
|
|
44
|
+
|
|
45
|
+
response = @http.get(url, params:)
|
|
46
|
+
handle_response(response)
|
|
47
|
+
rescue ArgumentError => e
|
|
48
|
+
logger.error('Invalid URL', url:, exception: e)
|
|
49
|
+
raise Error, "Invalid URL: #{e.message}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def market
|
|
53
|
+
@market ||= Market::Client.new(clone)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def search
|
|
57
|
+
@search ||= Search::Client.new(clone)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def events
|
|
61
|
+
@events ||= Events::Client.new(clone)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def series
|
|
65
|
+
@series ||= Series::Client.new(clone)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def full_url(path)
|
|
71
|
+
parts = [base_url, prefix, path].compact
|
|
72
|
+
parts.reject!(&:empty?)
|
|
73
|
+
File.join(*parts)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def handle_response(response)
|
|
77
|
+
response.raise_for_status
|
|
78
|
+
JSON.parse(response.body.to_s, symbolize_names: true)
|
|
79
|
+
rescue HTTPX::HTTPError => e
|
|
80
|
+
logger.error('API Error', e)
|
|
81
|
+
raise Error, "API Error: #{e.response.status} - #{e.response.body}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'reform'
|
|
4
|
+
require 'reform/form/dry'
|
|
5
|
+
|
|
6
|
+
module Rubyists
|
|
7
|
+
module Kalshi
|
|
8
|
+
# Base Contract class for Trailblazer/Reform forms
|
|
9
|
+
class Contract < Reform::Form
|
|
10
|
+
feature Reform::Form::Dry
|
|
11
|
+
|
|
12
|
+
# Custom class methods can be defined here
|
|
13
|
+
module ClassMethods
|
|
14
|
+
def propertize(*names)
|
|
15
|
+
# names is always an array because of the splat
|
|
16
|
+
names = names.flatten
|
|
17
|
+
const_set(:Properties, Struct.new(*custom_definitions, *names, keyword_init: true))
|
|
18
|
+
names.each { |name| property name, populator: ->(value:, **) { value || skip! } }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.inherited(subclass)
|
|
23
|
+
subclass.extend ClassMethods
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.custom_definitions = instance_variable_get(:@definitions)&.keys&.map(&:to_sym) || []
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
to_nested_hash.compact
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
# Base class for Kalshi API endpoints
|
|
6
|
+
class Endpoint
|
|
7
|
+
attr_reader :client
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
attr_accessor :endpoint_path
|
|
11
|
+
|
|
12
|
+
# Set the endpoint path for the resource
|
|
13
|
+
#
|
|
14
|
+
# @param path [String] API endpoint path
|
|
15
|
+
#
|
|
16
|
+
# @return [String] endpoint path
|
|
17
|
+
def kalshi_path(path)
|
|
18
|
+
self.endpoint_path = path
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Initialize the Endpoint
|
|
23
|
+
#
|
|
24
|
+
# @param client [Client] The Kalshi client
|
|
25
|
+
#
|
|
26
|
+
# @return [void]
|
|
27
|
+
def initialize(client = nil)
|
|
28
|
+
@client = client || Client.new
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Events
|
|
6
|
+
# Events API Client
|
|
7
|
+
class Client < ApiClient
|
|
8
|
+
def list(...)
|
|
9
|
+
List.new(client).list(...)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def fetch(...)
|
|
13
|
+
List.new(client).fetch(...)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def metadata(...)
|
|
17
|
+
List.new(client).metadata(...)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def multivariate
|
|
21
|
+
Multivariate.new(client)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def candlesticks
|
|
25
|
+
Rubyists::Kalshi::Series::EventCandlesticks.new(client)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Events
|
|
6
|
+
# Events API endpoint
|
|
7
|
+
class List < Kalshi::Endpoint
|
|
8
|
+
include Kalshi::Listable
|
|
9
|
+
|
|
10
|
+
kalshi_path ''
|
|
11
|
+
|
|
12
|
+
# Filter for Kalshi events list
|
|
13
|
+
class Filter < Kalshi::Contract
|
|
14
|
+
propertize(%i[limit cursor status series_ticker with_nested_markets])
|
|
15
|
+
|
|
16
|
+
validation do
|
|
17
|
+
params do
|
|
18
|
+
optional(:limit).maybe(:integer)
|
|
19
|
+
optional(:cursor).maybe(:string)
|
|
20
|
+
optional(:status).maybe(:string)
|
|
21
|
+
optional(:series_ticker).maybe(:string)
|
|
22
|
+
optional(:with_nested_markets).maybe(:bool)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def fetch(event_ticker)
|
|
28
|
+
client.get(event_ticker)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def metadata(event_ticker)
|
|
32
|
+
client.get("#{event_ticker}/metadata")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Events
|
|
6
|
+
# Multivariate Events API endpoint
|
|
7
|
+
class Multivariate < Kalshi::Endpoint
|
|
8
|
+
include Kalshi::Listable
|
|
9
|
+
|
|
10
|
+
kalshi_path 'multivariate'
|
|
11
|
+
|
|
12
|
+
# Filter for Kalshi multivariate events list
|
|
13
|
+
class Filter < Kalshi::Contract
|
|
14
|
+
propertize(%i[limit cursor series_ticker collection_ticker])
|
|
15
|
+
|
|
16
|
+
validation do
|
|
17
|
+
params do
|
|
18
|
+
optional(:limit).maybe(:integer)
|
|
19
|
+
optional(:cursor).maybe(:string)
|
|
20
|
+
optional(:series_ticker).maybe(:string)
|
|
21
|
+
optional(:collection_ticker).maybe(:string)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
# Mixin for listable resources
|
|
6
|
+
module Listable
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.extend(ClassMethods)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Class methods for Listable
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def list(...)
|
|
14
|
+
new.list(...)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# List resources
|
|
19
|
+
#
|
|
20
|
+
# @param filter [Filter|Hash] Filter options
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash|Array] resource data
|
|
23
|
+
def list(filter = self.class::Filter.new(self.class::Filter::Properties.new))
|
|
24
|
+
filter = self.class::Filter.new(self.class::Filter::Properties.new(**filter)) if filter.is_a?(Hash)
|
|
25
|
+
raise ArgumentError, filter.errors.full_messages.join(', ') unless filter.validate({})
|
|
26
|
+
|
|
27
|
+
client.get(self.class.endpoint_path, params: filter.to_h)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Market
|
|
6
|
+
# Market API Client
|
|
7
|
+
class Client
|
|
8
|
+
attr_reader :client
|
|
9
|
+
|
|
10
|
+
def initialize(client)
|
|
11
|
+
@client = client
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def series_list
|
|
15
|
+
@series_list ||= SeriesList.new(client)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def series
|
|
19
|
+
@series ||= Series.new(client)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def markets
|
|
23
|
+
@markets ||= Markets.new(client)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def orderbook
|
|
27
|
+
@orderbook ||= Orderbook.new(client)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def trades
|
|
31
|
+
@trades ||= Trades.new(client)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def candlesticks
|
|
35
|
+
@candlesticks ||= Rubyists::Kalshi::Series::MarketCandlesticks.new(client)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Market
|
|
6
|
+
# Markets API endpoint
|
|
7
|
+
class Markets < Kalshi::Endpoint
|
|
8
|
+
include Kalshi::Listable
|
|
9
|
+
|
|
10
|
+
kalshi_path 'markets'
|
|
11
|
+
|
|
12
|
+
# Filter for Kalshi markets list
|
|
13
|
+
class Filter < Kalshi::Contract
|
|
14
|
+
propertize(%i[limit cursor event_ticker series_ticker max_close_ts min_close_ts status tickers])
|
|
15
|
+
|
|
16
|
+
validation do
|
|
17
|
+
params do
|
|
18
|
+
optional(:limit).maybe(:integer)
|
|
19
|
+
optional(:cursor).maybe(:string)
|
|
20
|
+
optional(:event_ticker).maybe(:string)
|
|
21
|
+
optional(:series_ticker).maybe(:string)
|
|
22
|
+
optional(:max_close_ts).maybe(:integer)
|
|
23
|
+
optional(:min_close_ts).maybe(:integer)
|
|
24
|
+
optional(:status).maybe(:string)
|
|
25
|
+
optional(:tickers).maybe(:string)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fetch(ticker)
|
|
31
|
+
client.get("markets/#{ticker}")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Market
|
|
6
|
+
# Orderbook API endpoint
|
|
7
|
+
class Orderbook < Kalshi::Endpoint
|
|
8
|
+
def fetch(ticker, depth: nil)
|
|
9
|
+
params = {}
|
|
10
|
+
params[:depth] = depth if depth
|
|
11
|
+
client.get("markets/#{ticker}/orderbook", params: params)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Market
|
|
6
|
+
# Series List API endpoint
|
|
7
|
+
class SeriesList < Kalshi::Endpoint
|
|
8
|
+
include Kalshi::Listable
|
|
9
|
+
|
|
10
|
+
kalshi_path 'series'
|
|
11
|
+
|
|
12
|
+
# Filter for Kalshi series list
|
|
13
|
+
class Filter < Kalshi::Contract
|
|
14
|
+
propertize(%i[category tags include_product_metadata isInitialized status])
|
|
15
|
+
|
|
16
|
+
validation do
|
|
17
|
+
params do
|
|
18
|
+
optional(:category).maybe(:string)
|
|
19
|
+
optional(:tags).maybe(:string)
|
|
20
|
+
optional(:include_product_metadata).maybe(:bool)
|
|
21
|
+
optional(:isInitialized).maybe(:bool)
|
|
22
|
+
optional(:status).maybe(:string)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Market
|
|
6
|
+
# Trades API endpoint
|
|
7
|
+
class Trades < Kalshi::Endpoint
|
|
8
|
+
include Kalshi::Listable
|
|
9
|
+
|
|
10
|
+
kalshi_path 'markets/trades'
|
|
11
|
+
|
|
12
|
+
# Filter for Kalshi trades list
|
|
13
|
+
class Filter < Kalshi::Contract
|
|
14
|
+
propertize(%i[limit cursor ticker min_ts max_ts])
|
|
15
|
+
|
|
16
|
+
validation do
|
|
17
|
+
params do
|
|
18
|
+
optional(:limit).maybe(:integer)
|
|
19
|
+
optional(:cursor).maybe(:string)
|
|
20
|
+
optional(:ticker).maybe(:string)
|
|
21
|
+
optional(:min_ts).maybe(:integer)
|
|
22
|
+
optional(:max_ts).maybe(:integer)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Search
|
|
6
|
+
# Search API Client
|
|
7
|
+
class Client < ApiClient
|
|
8
|
+
def tags_by_categories
|
|
9
|
+
SeriesTags.new(client).all
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def filters_by_sport
|
|
13
|
+
SportsFilters.new(client).all
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Series
|
|
6
|
+
# Series API Client
|
|
7
|
+
class Client < ApiClient
|
|
8
|
+
def event_candlesticks
|
|
9
|
+
EventCandlesticks.new(client)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def forecast_percentile_history
|
|
13
|
+
ForecastPercentileHistory.new(client)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Series
|
|
6
|
+
# Event Candlesticks API endpoint
|
|
7
|
+
class EventCandlesticks < Kalshi::Endpoint
|
|
8
|
+
# Filter for Event Candlesticks
|
|
9
|
+
class EventFilter < Kalshi::Contract
|
|
10
|
+
propertize(%i[series_ticker ticker start_ts end_ts period_interval])
|
|
11
|
+
|
|
12
|
+
validation do
|
|
13
|
+
params do
|
|
14
|
+
required(:series_ticker).filled(:string)
|
|
15
|
+
required(:ticker).filled(:string)
|
|
16
|
+
required(:start_ts).filled(:integer)
|
|
17
|
+
required(:end_ts).filled(:integer)
|
|
18
|
+
required(:period_interval).filled(:integer)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def fetch(params)
|
|
24
|
+
filter = EventFilter.new(EventFilter::Properties.new(**params))
|
|
25
|
+
raise ArgumentError, filter.errors.full_messages.join(', ') unless filter.validate({})
|
|
26
|
+
|
|
27
|
+
path = "#{filter.series_ticker}/events/#{filter.ticker}/candlesticks"
|
|
28
|
+
query_params = filter.to_h.slice('start_ts', 'end_ts', 'period_interval')
|
|
29
|
+
client.get(path, params: query_params)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Series
|
|
6
|
+
# Event Forecast Percentile History API endpoint
|
|
7
|
+
class ForecastPercentileHistory < Kalshi::Endpoint
|
|
8
|
+
# Filter for Event Forecast Percentile History
|
|
9
|
+
class EventFilter < Kalshi::Contract
|
|
10
|
+
propertize(%i[series_ticker ticker percentiles start_ts end_ts period_interval])
|
|
11
|
+
|
|
12
|
+
validation do
|
|
13
|
+
params do
|
|
14
|
+
required(:series_ticker).filled(:string)
|
|
15
|
+
required(:ticker).filled(:string)
|
|
16
|
+
required(:percentiles).filled(:array)
|
|
17
|
+
required(:start_ts).filled(:integer)
|
|
18
|
+
required(:end_ts).filled(:integer)
|
|
19
|
+
required(:period_interval).filled(:integer)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def fetch(params)
|
|
25
|
+
filter = EventFilter.new(EventFilter::Properties.new(**params))
|
|
26
|
+
raise ArgumentError, filter.errors.full_messages.join(', ') unless filter.validate({})
|
|
27
|
+
|
|
28
|
+
path = "#{filter.series_ticker}/events/#{filter.ticker}/forecast_percentile_history"
|
|
29
|
+
query_params = filter.to_h.slice('start_ts', 'end_ts', 'period_interval')
|
|
30
|
+
query_params[:percentiles] = filter.percentiles.join(',')
|
|
31
|
+
client.get(path, params: query_params)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubyists
|
|
4
|
+
module Kalshi
|
|
5
|
+
module Series
|
|
6
|
+
# Candlesticks API endpoint
|
|
7
|
+
class MarketCandlesticks < Kalshi::Endpoint
|
|
8
|
+
def fetch(series_ticker:, ticker:, start_ts:, end_ts:, period_interval:)
|
|
9
|
+
path = "series/#{series_ticker}/markets/#{ticker}/candlesticks"
|
|
10
|
+
params = { start_ts:, end_ts:, period_interval: }
|
|
11
|
+
client.get(path, params:)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def batch(tickers:, series_ticker:, start_ts:, end_ts:, period_interval:)
|
|
15
|
+
path = 'markets/candlesticks'
|
|
16
|
+
params = {
|
|
17
|
+
market_tickers: tickers.is_a?(Array) ? tickers.join(',') : tickers,
|
|
18
|
+
series_ticker:,
|
|
19
|
+
start_ts:,
|
|
20
|
+
end_ts:,
|
|
21
|
+
period_interval:
|
|
22
|
+
}
|
|
23
|
+
client.get(path, params:)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|