dtn 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +21 -5
  3. data/.env.example +5 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +7 -0
  6. data/CHANGELOG.md +5 -1
  7. data/Gemfile +3 -1
  8. data/README.md +288 -9
  9. data/Rakefile +2 -0
  10. data/docker-compose.yml +34 -0
  11. data/dtn.gemspec +1 -1
  12. data/lib/dtn.rb +18 -1
  13. data/lib/dtn/concerns/id.rb +36 -0
  14. data/lib/dtn/concerns/validation.rb +71 -0
  15. data/lib/dtn/helpers/catalog.rb +32 -0
  16. data/lib/dtn/lookups/catalog/listed_markets.rb +12 -0
  17. data/lib/dtn/lookups/catalog/naic_codes.rb +12 -0
  18. data/lib/dtn/lookups/catalog/security_types.rb +12 -0
  19. data/lib/dtn/lookups/catalog/sic_codes.rb +12 -0
  20. data/lib/dtn/lookups/catalog/trade_conditions.rb +12 -0
  21. data/lib/dtn/lookups/historical/base.rb +43 -0
  22. data/lib/dtn/lookups/historical/daily_datapoint.rb +13 -0
  23. data/lib/dtn/lookups/historical/daily_timeframe.rb +34 -0
  24. data/lib/dtn/lookups/historical/datapoint.rb +27 -0
  25. data/lib/dtn/lookups/historical/interval.rb +14 -0
  26. data/lib/dtn/lookups/historical/interval_datapoint.rb +31 -0
  27. data/lib/dtn/lookups/historical/interval_day.rb +32 -0
  28. data/lib/dtn/lookups/historical/interval_timeframe.rb +37 -0
  29. data/lib/dtn/lookups/historical/monthly_datapoint.rb +13 -0
  30. data/lib/dtn/lookups/historical/tick.rb +14 -0
  31. data/lib/dtn/lookups/historical/tick_datapoint.rb +24 -0
  32. data/lib/dtn/lookups/historical/tick_day.rb +34 -0
  33. data/lib/dtn/lookups/historical/tick_timeframe.rb +31 -0
  34. data/lib/dtn/lookups/historical/weekly_datapoint.rb +13 -0
  35. data/lib/dtn/lookups/news/base.rb +85 -0
  36. data/lib/dtn/lookups/news/config.rb +25 -0
  37. data/lib/dtn/lookups/news/headline.rb +40 -0
  38. data/lib/dtn/lookups/news/story.rb +40 -0
  39. data/lib/dtn/lookups/news/story_count.rb +36 -0
  40. data/lib/dtn/lookups/request.rb +92 -0
  41. data/lib/dtn/lookups/symbol/base.rb +11 -0
  42. data/lib/dtn/lookups/symbol/by_filter.rb +58 -0
  43. data/lib/dtn/lookups/symbol/by_naic.rb +26 -0
  44. data/lib/dtn/lookups/symbol/by_sic.rb +26 -0
  45. data/lib/dtn/message.rb +29 -0
  46. data/lib/dtn/messages/bar/base.rb +30 -0
  47. data/lib/dtn/messages/bar/current_bar.rb +11 -0
  48. data/lib/dtn/messages/bar/historical_bar.rb +11 -0
  49. data/lib/dtn/messages/bar/update_bar.rb +11 -0
  50. data/lib/dtn/messages/catalog/code.rb +22 -0
  51. data/lib/dtn/messages/catalog/listed_markets.rb +20 -0
  52. data/lib/dtn/messages/catalog/naic_codes.rb +10 -0
  53. data/lib/dtn/messages/catalog/security_types.rb +20 -0
  54. data/lib/dtn/messages/catalog/sic_codes.rb +10 -0
  55. data/lib/dtn/messages/catalog/trade_conditions.rb +20 -0
  56. data/lib/dtn/messages/historical/daily_weekly_monthly.rb +25 -0
  57. data/lib/dtn/messages/historical/interval.rb +28 -0
  58. data/lib/dtn/messages/historical/tick.rb +31 -0
  59. data/lib/dtn/messages/level2/level2_update.rb +38 -0
  60. data/lib/dtn/messages/level2/market_maker_name.rb +20 -0
  61. data/lib/dtn/messages/message_with_simple_parser.rb +38 -0
  62. data/lib/dtn/messages/news/base.rb +34 -0
  63. data/lib/dtn/messages/news/config.rb +24 -0
  64. data/lib/dtn/messages/news/headline.rb +25 -0
  65. data/lib/dtn/messages/news/story.rb +20 -0
  66. data/lib/dtn/messages/news/story_count.rb +21 -0
  67. data/lib/dtn/messages/quote/level1.rb +150 -0
  68. data/lib/dtn/messages/quote/level1_fundamental.rb +17 -0
  69. data/lib/dtn/messages/quote/level1_news.rb +27 -0
  70. data/lib/dtn/messages/quote/level1_regional.rb +31 -0
  71. data/lib/dtn/messages/quote/level1_summary.rb +19 -0
  72. data/lib/dtn/messages/quote/level1_update.rb +21 -0
  73. data/lib/dtn/messages/symbol/base.rb +35 -0
  74. data/lib/dtn/messages/symbol/by_filter.rb +11 -0
  75. data/lib/dtn/messages/symbol/by_naic.rb +22 -0
  76. data/lib/dtn/messages/symbol/by_sic.rb +22 -0
  77. data/lib/dtn/messages/system/client_stats.rb +46 -0
  78. data/lib/dtn/messages/system/customer_info.rb +30 -0
  79. data/lib/dtn/messages/system/end_of_message_characters.rb +22 -0
  80. data/lib/dtn/messages/system/error.rb +20 -0
  81. data/lib/dtn/messages/system/generic.rb +98 -0
  82. data/lib/dtn/messages/system/no_data_characters.rb +22 -0
  83. data/lib/dtn/messages/system/stats.rb +38 -0
  84. data/lib/dtn/messages/system/symbol_not_found.rb +19 -0
  85. data/lib/dtn/messages/system/timestamp.rb +16 -0
  86. data/lib/dtn/messages/unknown.rb +15 -0
  87. data/lib/dtn/registry.rb +57 -0
  88. data/lib/dtn/streaming/client.rb +105 -0
  89. data/lib/dtn/streaming/clients/admin.rb +20 -0
  90. data/lib/dtn/streaming/clients/bar.rb +49 -0
  91. data/lib/dtn/streaming/clients/level2.rb +25 -0
  92. data/lib/dtn/streaming/clients/quote.rb +57 -0
  93. data/lib/dtn/streaming/messages_recorder_observer.rb +26 -0
  94. data/lib/dtn/streaming/request.rb +27 -0
  95. data/lib/dtn/streaming/request_builder.rb +57 -0
  96. data/lib/dtn/streaming/requests/admin/register_client_app.rb +24 -0
  97. data/lib/dtn/streaming/requests/admin/remove_client_app.rb +22 -0
  98. data/lib/dtn/streaming/requests/admin/save_login_info.rb +18 -0
  99. data/lib/dtn/streaming/requests/admin/set_autoconnect.rb +18 -0
  100. data/lib/dtn/streaming/requests/admin/set_client_stats.rb +20 -0
  101. data/lib/dtn/streaming/requests/admin/set_loginid.rb +21 -0
  102. data/lib/dtn/streaming/requests/admin/set_password.rb +21 -0
  103. data/lib/dtn/streaming/requests/bar/unwatch.rb +18 -0
  104. data/lib/dtn/streaming/requests/bar/unwatch_all.rb +16 -0
  105. data/lib/dtn/streaming/requests/bar/watch.rb +81 -0
  106. data/lib/dtn/streaming/requests/bar/watches.rb +21 -0
  107. data/lib/dtn/streaming/requests/level2/connect.rb +16 -0
  108. data/lib/dtn/streaming/requests/level2/disconnect.rb +16 -0
  109. data/lib/dtn/streaming/requests/level2/market_maker_by_id.rb +18 -0
  110. data/lib/dtn/streaming/requests/level2/unwatch.rb +18 -0
  111. data/lib/dtn/streaming/requests/level2/watch.rb +18 -0
  112. data/lib/dtn/streaming/requests/quote/all_update_fieldnames.rb +16 -0
  113. data/lib/dtn/streaming/requests/quote/connect.rb +16 -0
  114. data/lib/dtn/streaming/requests/quote/current_update_fieldnames.rb +16 -0
  115. data/lib/dtn/streaming/requests/quote/fundamental_fieldnames.rb +16 -0
  116. data/lib/dtn/streaming/requests/quote/news_switch.rb +18 -0
  117. data/lib/dtn/streaming/requests/quote/refresh.rb +29 -0
  118. data/lib/dtn/streaming/requests/quote/regional_switch.rb +26 -0
  119. data/lib/dtn/streaming/requests/quote/set_client_name.rb +16 -0
  120. data/lib/dtn/streaming/requests/quote/set_protocol.rb +16 -0
  121. data/lib/dtn/streaming/requests/quote/timestamp.rb +21 -0
  122. data/lib/dtn/streaming/requests/quote/timestamp_switch.rb +18 -0
  123. data/lib/dtn/streaming/requests/quote/trades.rb +21 -0
  124. data/lib/dtn/streaming/requests/quote/unwatch.rb +22 -0
  125. data/lib/dtn/streaming/requests/quote/unwatch_all.rb +16 -0
  126. data/lib/dtn/streaming/requests/quote/update_fields.rb +40 -0
  127. data/lib/dtn/streaming/requests/quote/watch.rb +22 -0
  128. data/lib/dtn/streaming/requests/quote/watches.rb +21 -0
  129. data/lib/dtn/version.rb +1 -1
  130. data/lib/ext/business_day.rb +15 -0
  131. data/lib/tasks/spec_date.rake +13 -0
  132. metadata +126 -6
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module Historical
6
+ # Bar representation
7
+ class Interval < MessageWithSimpleParser
8
+ class << self
9
+ # rubocop:disable Metrics/MethodLength
10
+ def fields
11
+ @fields ||= {
12
+ request_id: :to_i,
13
+ timestamp: :to_datetime,
14
+ high: :to_f,
15
+ low: :to_f,
16
+ open: :to_f,
17
+ close: :to_f,
18
+ total_volume: :to_i,
19
+ period_volume: :to_i,
20
+ number_of_trades: :to_i
21
+ }
22
+ end
23
+ # rubocop:enable Metrics/MethodLength
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module Historical
6
+ # Price tick message abstraction.
7
+ class Tick < MessageWithSimpleParser
8
+ class << self
9
+ # rubocop:disable Metrics/MethodLength
10
+ def fields
11
+ @fields ||= {
12
+ request_id: :to_i,
13
+ timestamp: :to_datetime,
14
+ last: :to_f,
15
+ last_size: :to_i,
16
+ total_volume: :to_i,
17
+ bid: :to_f,
18
+ ask: :to_f,
19
+ tick_id: :to_i,
20
+ basis_for_last: :to_s,
21
+ trade_market_center: :to_s,
22
+ trade_aggressor: :to_s,
23
+ day_code: :to_s
24
+ }
25
+ end
26
+ # rubocop:enable Metrics/MethodLength
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module Level2
6
+ # Streaming level2 update
7
+ class Level2Update < MessageWithSimpleParser
8
+ class << self
9
+ # rubocop:disable Metrics/MethodLength
10
+ def fields
11
+ @fields ||= {
12
+ _skip: :nil,
13
+ symbol: :to_s,
14
+ mmid: :to_s,
15
+ bid: :to_f,
16
+ ask: :to_f,
17
+ bid_size: :to_i,
18
+ ask_size: :to_i,
19
+ bid_time: :to_s,
20
+ date: :to_s,
21
+ unknown1: :to_s,
22
+ trade_condition_id: :to_i,
23
+ unknown3: :to_s,
24
+ ask_time: :to_s,
25
+ unknown4: :to_s,
26
+ unknown5: :to_s
27
+ }
28
+ end
29
+ # rubocop:enable Metrics/MethodLength
30
+ end
31
+
32
+ def trade_condition
33
+ Dtn.trade_conditions_catalog[trade_condition_id]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module Level2
6
+ # Streaming level2 MarketMakerName
7
+ class MarketMakerName < MessageWithSimpleParser
8
+ class << self
9
+ def fields
10
+ @fields ||= {
11
+ _skip: :nil,
12
+ mmid: :to_s,
13
+ description: :to_s
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ # Lookup Message abstraction
6
+ class MessageWithSimpleParser < Message
7
+ class << self
8
+ def parse(line:, request: nil, **)
9
+ values = line.split(",")
10
+
11
+ new.tap do |n|
12
+ apply_values instance: n, attributes: fields, values: values
13
+ if respond_to?(:parse_dynamic_fields)
14
+ parse_dynamic_fields(instance: n, values: values[(fields.size)..], request: request)
15
+ end
16
+ n.after_initialization if n.respond_to?(:after_initialization)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def apply_values(instance:, attributes:, values:)
23
+ attributes.zip(values).each do |(attr, converter), value|
24
+ next if attr.to_s.start_with?("_")
25
+
26
+ instance.public_send("#{attr}=", value.public_send(converter))
27
+ end
28
+ end
29
+ end
30
+
31
+ # After receiving termination Message Request will be marked as finished and #each
32
+ # method successfully finalize the iteration
33
+ def termination?
34
+ false
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module News
6
+ # Base
7
+ class Base < MessageWithSimpleParser
8
+ class << self
9
+ def fields
10
+ @fields ||= { request_id: :to_i }
11
+ end
12
+
13
+ def parse_dynamic_fields(instance:, values:, request:)
14
+ attributes = case request.combined_options[:format_type]
15
+ when "t" then text_fields
16
+ when "x" then xml_fields
17
+ else raise "Wrong format type"
18
+ end
19
+
20
+ apply_values instance: instance, attributes: attributes, values: values
21
+ end
22
+
23
+ private
24
+
25
+ def xml_fields
26
+ {
27
+ xml: :to_s
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module News
6
+ # News config
7
+ class Config < Base
8
+ class << self
9
+ private
10
+
11
+ def text_fields
12
+ {
13
+ category: :to_s,
14
+ type: :to_s,
15
+ name: :to_s,
16
+ auth_code: :to_s,
17
+ icon_id: :to_s
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module News
6
+ # News headline
7
+ class Headline < Base
8
+ class << self
9
+ private
10
+
11
+ def text_fields
12
+ {
13
+ _skip: :to_s,
14
+ source: :to_s,
15
+ story_id: :to_s,
16
+ symbols: :to_s,
17
+ timestamp: :to_datetime,
18
+ text: :to_s
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module News
6
+ # News story
7
+ class Story < Base
8
+ class << self
9
+ private
10
+
11
+ def text_fields
12
+ {
13
+ text: :to_s
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dtn
4
+ module Messages
5
+ module News
6
+ # News story count
7
+ class StoryCount < Base
8
+ class << self
9
+ private
10
+
11
+ def text_fields
12
+ {
13
+ description: :to_s,
14
+ count: :to_i
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/ClassLength
4
+ module Dtn
5
+ module Messages
6
+ module Quote
7
+ # Streaming level1 dynamic data
8
+ class Level1 < MessageWithSimpleParser
9
+ # fetched with Streaming::Clients::Quote.new.request.quote.all_update_fieldnames
10
+ # and stored this way to been able to store the returning types
11
+ ALL_FIELDS = {
12
+ "_skip" => nil,
13
+ "Symbol" => :to_s,
14
+ "Exchange ID" => :to_i,
15
+ "Last" => :to_f,
16
+ "Change" => :to_f,
17
+ "Percent Change" => :to_f,
18
+ "Total Volume" => :to_i,
19
+ "High" => :to_f,
20
+ "Low" => :to_f,
21
+ "Bid" => :to_f,
22
+ "Ask" => :to_f,
23
+ "Bid Size" => :to_i,
24
+ "Ask Size" => :to_i,
25
+ "Tick" => :to_s,
26
+ "Range" => :to_s,
27
+ "Open Interest" => :to_s,
28
+ "Open" => :to_f,
29
+ "Close" => :to_f,
30
+ "Spread" => :to_f,
31
+ "Settle" => :to_s,
32
+ "Delay" => :to_s,
33
+ "Restricted Code" => :to_s,
34
+ "Net Asset Value" => :to_s,
35
+ "Average Maturity" => :to_s,
36
+ "7 Day Yield" => :to_s,
37
+ "Extended Trading Change" => :to_s,
38
+ "Extended Trading Difference" => :to_s,
39
+ "Price-Earnings Ratio" => :to_s,
40
+ "Percent Off Average Volume" => :to_s,
41
+ "Bid Change" => :to_f,
42
+ "Ask Change" => :to_f,
43
+ "Change From Open" => :to_f,
44
+ "Market Open" => :to_s,
45
+ "Volatility" => :to_s,
46
+ "Market Capitalization" => :to_f,
47
+ "Fraction Display Code" => :to_s,
48
+ "Decimal Precision" => :to_i,
49
+ "Days to Expiration" => :to_s,
50
+ "Previous Day Volume" => :to_i,
51
+ "Open Range 1" => :to_s,
52
+ "Close Range 1" => :to_s,
53
+ "Open Range 2" => :to_s,
54
+ "Close Range 2" => :to_s,
55
+ "Number of Trades Today" => :to_i,
56
+ "VWAP" => :to_f,
57
+ "TickID" => :to_s,
58
+ "Financial Status Indicator" => :to_s,
59
+ "Settlement Date" => :to_s,
60
+ "Bid Market Center" => :to_s,
61
+ "Ask Market Center" => :to_s,
62
+ "Available Regions" => :to_s,
63
+ "Last Size" => :to_i,
64
+ "Last Time" => :to_s,
65
+ "Last Market Center" => :to_s,
66
+ "Most Recent Trade" => :to_s,
67
+ "Most Recent Trade Size" => :to_s,
68
+ "Most Recent Trade Time" => :to_s,
69
+ "Most Recent Trade Conditions" => :to_s,
70
+ "Most Recent Trade Market Center" => :to_s,
71
+ "Extended Trade" => :to_s,
72
+ "Extended Trade Size" => :to_s,
73
+ "Extended Trade Time" => :to_s,
74
+ "Extended Trade Market Center" => :to_s,
75
+ "Message Contents" => :to_s,
76
+ "Ask Time" => :to_s,
77
+ "Bid Time" => :to_s,
78
+ "Last Date" => :to_s,
79
+ "Extended Trade Date" => :to_s,
80
+ "Most Recent Trade Date" => :to_s,
81
+ "Most Recent Trade Aggressor" => :to_s,
82
+ "Most Recent Trade Day Code" => :to_s
83
+ }.freeze
84
+
85
+ # cached from `client.request.quote.fundamental_fieldnames`
86
+ ALL_FUNDAMENTAL_FIELDS = {
87
+ "_skip" => nil,
88
+ "Symbol" => :to_s,
89
+ "Exchange ID" => :to_i,
90
+ "PE" => :to_f,
91
+ "Average Volume" => :to_i,
92
+ "52 Week High" => :to_f,
93
+ "52 Week Low" => :to_f,
94
+ "Calendar Year High" => :to_f,
95
+ "Calendar Year Low" => :to_f,
96
+ "Dividend Yield" => :to_s,
97
+ "Dividend Amount" => :to_s,
98
+ "Dividend Rate" => :to_s,
99
+ "Pay Date" => :to_s,
100
+ "Ex-dividend Date" => :to_s,
101
+ "Current Year EPS" => :to_f,
102
+ "Next Year EPS" => :to_f,
103
+ "Five-year Growth Percentage" => :to_f,
104
+ "Fiscal Year End" => :to_i,
105
+ "Company Name" => :to_s,
106
+ "Root Option Symbol" => :to_s,
107
+ "Percent Held By Institutions" => :to_f,
108
+ "Beta" => :to_f,
109
+ "Leaps" => :to_s,
110
+ "Current Assets" => :to_f,
111
+ "Current Liabilities" => :to_f,
112
+ "Balance Sheet Date" => :to_s,
113
+ "Long-term Debt" => :to_f,
114
+ "Common Shares Outstanding" => :to_i,
115
+ "Split Factor 1" => :to_s,
116
+ "Split Factor 2" => :to_s,
117
+ "Format Code" => :to_i,
118
+ "Precision" => :to_i,
119
+ "SIC" => :to_i,
120
+ "Historical Volatility" => :to_f,
121
+ "Security Type" => :to_i,
122
+ "Listed Market" => :to_i,
123
+ "52 Week High Date" => :to_s,
124
+ "52 Week Low Date" => :to_s,
125
+ "Calendar Year High Date" => :to_s,
126
+ "Calendar Year Low Date" => :to_s,
127
+ "Year End Close" => :to_f,
128
+ "Maturity Date" => :to_s,
129
+ "Coupon Rate" => :to_s,
130
+ "Expiration Date" => :to_s,
131
+ "Strike Price" => :to_s,
132
+ "NAICS" => :to_s,
133
+ "Exchange Root" => :to_s,
134
+ "Option Premium Multiplier" => :to_s,
135
+ "Option Multiple Deliverable" => :to_s,
136
+ "Session Open Time" => :to_s,
137
+ "Session Close Time" => :to_s,
138
+ "Base Currency" => :to_s,
139
+ "Contract Size" => :to_s,
140
+ "Contract Months" => :to_s,
141
+ "Minimum Tick Size" => :to_s,
142
+ "First Delivery Date" => :to_s,
143
+ "FIGI" => :to_s,
144
+ "Security SubType" => :to_s
145
+ }.freeze
146
+ end
147
+ end
148
+ end
149
+ end
150
+ # rubocop:enable Metrics/ClassLength