kbs 0.0.1 → 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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +52 -0
  3. data/CHANGELOG.md +68 -2
  4. data/README.md +235 -334
  5. data/docs/DOCUMENTATION_STATUS.md +158 -0
  6. data/docs/advanced/custom-persistence.md +775 -0
  7. data/docs/advanced/debugging.md +726 -0
  8. data/docs/advanced/index.md +8 -0
  9. data/docs/advanced/performance.md +832 -0
  10. data/docs/advanced/testing.md +691 -0
  11. data/docs/api/blackboard.md +1157 -0
  12. data/docs/api/engine.md +978 -0
  13. data/docs/api/facts.md +1212 -0
  14. data/docs/api/index.md +12 -0
  15. data/docs/api/rules.md +1034 -0
  16. data/docs/architecture/blackboard.md +553 -0
  17. data/docs/architecture/index.md +277 -0
  18. data/docs/architecture/network-structure.md +343 -0
  19. data/docs/architecture/rete-algorithm.md +737 -0
  20. data/docs/assets/css/custom.css +83 -0
  21. data/docs/assets/images/blackboard-architecture.svg +136 -0
  22. data/docs/assets/images/compiled-network.svg +101 -0
  23. data/docs/assets/images/fact-assertion-flow.svg +117 -0
  24. data/docs/assets/images/kbs.jpg +0 -0
  25. data/docs/assets/images/pattern-matching-trace.svg +136 -0
  26. data/docs/assets/images/rete-network-layers.svg +96 -0
  27. data/docs/assets/images/system-layers.svg +69 -0
  28. data/docs/assets/images/trading-signal-network.svg +139 -0
  29. data/docs/assets/js/mathjax.js +17 -0
  30. data/docs/examples/expert-systems.md +1031 -0
  31. data/docs/examples/index.md +9 -0
  32. data/docs/examples/multi-agent.md +1335 -0
  33. data/docs/examples/stock-trading.md +488 -0
  34. data/docs/guides/blackboard-memory.md +558 -0
  35. data/docs/guides/dsl.md +1321 -0
  36. data/docs/guides/facts.md +652 -0
  37. data/docs/guides/getting-started.md +383 -0
  38. data/docs/guides/index.md +23 -0
  39. data/docs/guides/negation.md +529 -0
  40. data/docs/guides/pattern-matching.md +561 -0
  41. data/docs/guides/persistence.md +451 -0
  42. data/docs/guides/variable-binding.md +491 -0
  43. data/docs/guides/writing-rules.md +755 -0
  44. data/docs/index.md +157 -0
  45. data/docs/installation.md +156 -0
  46. data/docs/quick-start.md +228 -0
  47. data/examples/README.md +2 -2
  48. data/examples/advanced_example.rb +2 -2
  49. data/examples/advanced_example_dsl.rb +224 -0
  50. data/examples/ai_enhanced_kbs.rb +1 -1
  51. data/examples/ai_enhanced_kbs_dsl.rb +538 -0
  52. data/examples/blackboard_demo_dsl.rb +50 -0
  53. data/examples/car_diagnostic.rb +1 -1
  54. data/examples/car_diagnostic_dsl.rb +54 -0
  55. data/examples/concurrent_inference_demo.rb +5 -5
  56. data/examples/concurrent_inference_demo_dsl.rb +363 -0
  57. data/examples/csv_trading_system.rb +1 -1
  58. data/examples/csv_trading_system_dsl.rb +525 -0
  59. data/examples/knowledge_base.db +0 -0
  60. data/examples/portfolio_rebalancing_system.rb +2 -2
  61. data/examples/portfolio_rebalancing_system_dsl.rb +613 -0
  62. data/examples/redis_trading_demo_dsl.rb +177 -0
  63. data/examples/run_all.rb +50 -0
  64. data/examples/run_all_dsl.rb +49 -0
  65. data/examples/stock_trading_advanced.rb +1 -1
  66. data/examples/stock_trading_advanced_dsl.rb +404 -0
  67. data/examples/temp.txt +7693 -0
  68. data/examples/temp_dsl.txt +8447 -0
  69. data/examples/timestamped_trading.rb +1 -1
  70. data/examples/timestamped_trading_dsl.rb +258 -0
  71. data/examples/trading_demo.rb +1 -1
  72. data/examples/trading_demo_dsl.rb +322 -0
  73. data/examples/working_demo.rb +1 -1
  74. data/examples/working_demo_dsl.rb +160 -0
  75. data/lib/kbs/blackboard/engine.rb +3 -3
  76. data/lib/kbs/blackboard/fact.rb +1 -1
  77. data/lib/kbs/condition.rb +1 -1
  78. data/lib/kbs/dsl/knowledge_base.rb +1 -1
  79. data/lib/kbs/dsl/variable.rb +1 -1
  80. data/lib/kbs/{rete_engine.rb → engine.rb} +1 -1
  81. data/lib/kbs/fact.rb +1 -1
  82. data/lib/kbs/version.rb +1 -1
  83. data/lib/kbs.rb +2 -2
  84. data/mkdocs.yml +181 -0
  85. metadata +66 -6
  86. data/examples/stock_trading_system.rb.bak +0 -563
@@ -5,7 +5,7 @@ require 'time'
5
5
 
6
6
  class TimestampedTradingSystem
7
7
  def initialize
8
- @engine = KBS::ReteEngine.new
8
+ @engine = KBS::Engine.new
9
9
  @market_open = Time.parse("09:30:00")
10
10
  @market_close = Time.parse("16:00:00")
11
11
  setup_time_aware_rules
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/kbs/dsl'
4
+ require 'time'
5
+
6
+ class TimestampedTradingSystem
7
+ include KBS::DSL::ConditionHelpers
8
+
9
+ def initialize
10
+ @kb = nil
11
+ @market_open = Time.parse("09:30:00")
12
+ @market_close = Time.parse("16:00:00")
13
+ setup_time_aware_rules
14
+ end
15
+
16
+ def format_volume(volume)
17
+ if volume >= 1_000_000
18
+ "#{(volume / 1_000_000.0).round(1)}M"
19
+ elsif volume >= 1_000
20
+ "#{(volume / 1_000.0).round(1)}K"
21
+ else
22
+ volume.to_s
23
+ end
24
+ end
25
+
26
+ def setup_time_aware_rules
27
+ ts_sys = self # Capture self for use in perform blocks
28
+ @kb = KBS.knowledge_base do
29
+ rule "fresh_momentum" do
30
+ priority 15
31
+ on :stock,
32
+ price_change: satisfies { |p| p && p > 2 },
33
+ timestamp: satisfies { |t| t && (Time.now - t) < 60 },
34
+ market_session: "regular"
35
+
36
+ perform do |facts|
37
+ stock = facts.find { |f| f.type == :stock }
38
+ age = Time.now - stock[:timestamp]
39
+ puts "🚀 FRESH MOMENTUM: #{stock[:symbol]}"
40
+ puts " Price Change: +#{stock[:price_change]}%"
41
+ puts " Data Age: #{age.round(1)} seconds"
42
+ puts " Market Time: #{stock[:market_time]}"
43
+ puts " Recommendation: BUY (fresh signal)"
44
+ end
45
+ end
46
+
47
+ rule "stale_data_warning" do
48
+ priority 20
49
+ on :stock, timestamp: satisfies { |t| t && (Time.now - t) > 300 }
50
+
51
+ perform do |facts|
52
+ stock = facts.find { |f| f.type == :stock }
53
+ age = Time.now - stock[:timestamp]
54
+ puts "⚠️ STALE DATA: #{stock[:symbol]}"
55
+ puts " Data Age: #{(age / 60).round(1)} minutes"
56
+ puts " Last Update: #{stock[:timestamp]}"
57
+ puts " ACTION: IGNORE - Data too old"
58
+ end
59
+ end
60
+
61
+ rule "market_hours_check" do
62
+ on :stock,
63
+ market_session: "after_hours",
64
+ volume: satisfies { |v| v && v > 100_000 }
65
+
66
+ perform do |facts|
67
+ stock = facts.find { |f| f.type == :stock }
68
+ puts "🌙 AFTER HOURS ACTIVITY: #{stock[:symbol]}"
69
+ puts " Volume: #{ts_sys.format_volume(stock[:volume])}"
70
+ puts " Time: #{stock[:market_time]}"
71
+ puts " ACTION: Monitor for gap potential"
72
+ end
73
+ end
74
+
75
+ rule "rapid_movement" do
76
+ on :price_tick,
77
+ time_delta: satisfies { |d| d && d < 5 },
78
+ price_delta: satisfies { |d| d && d.abs > 0.50 }
79
+
80
+ perform do |facts|
81
+ tick = facts.find { |f| f.type == :price_tick }
82
+ direction = tick[:price_delta] > 0 ? "📈 UP" : "📉 DOWN"
83
+ puts "⚡ RAPID MOVEMENT: #{tick[:symbol]} #{direction}"
84
+ puts " Price Change: #{tick[:price_delta] > 0 ? '+' : ''}$#{tick[:price_delta]}"
85
+ puts " Time Frame: #{tick[:time_delta]} seconds"
86
+ puts " ACTION: Check for news catalyst"
87
+ end
88
+ end
89
+
90
+ rule "opening_gap" do
91
+ on :stock,
92
+ market_time: satisfies { |t|
93
+ t && (t.hour == 9 && t.min >= 30 && t.min <= 35)
94
+ },
95
+ gap_percentage: satisfies { |g| g && g.abs > 1 }
96
+
97
+ perform do |facts|
98
+ stock = facts.find { |f| f.type == :stock }
99
+ direction = stock[:gap_percentage] > 0 ? "GAP UP" : "GAP DOWN"
100
+ puts "🔔 OPENING #{direction}: #{stock[:symbol]}"
101
+ puts " Gap: #{stock[:gap_percentage] > 0 ? '+' : ''}#{stock[:gap_percentage]}%"
102
+ puts " Time: #{stock[:market_time]}"
103
+ puts " Volume: #{ts_sys.format_volume(stock[:volume])}"
104
+ puts " ACTION: Monitor for gap fill or continuation"
105
+ end
106
+ end
107
+
108
+ rule "end_of_day" do
109
+ on :stock, market_time: satisfies { |t|
110
+ t && (t.hour == 15 && t.min >= 45)
111
+ }
112
+ on :position, status: "open"
113
+
114
+ perform do |facts|
115
+ stock = facts.find { |f| f.type == :stock }
116
+ position = facts.find { |f| f.type == :position }
117
+ puts "🕐 END OF DAY: #{position[:symbol]}"
118
+ puts " Current Time: #{stock[:market_time]}"
119
+ puts " Position P&L: #{position[:unrealized_pnl]}"
120
+ puts " ACTION: Consider closing before market close"
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ def determine_market_session(time)
127
+ hour_min = time.hour * 100 + time.min
128
+
129
+ case hour_min
130
+ when 400..929 then "pre_market"
131
+ when 930..1559 then "regular"
132
+ when 1600..2000 then "after_hours"
133
+ else "closed"
134
+ end
135
+ end
136
+
137
+ def add_timestamped_stock_fact(symbol, price, volume, options = {})
138
+ timestamp = options[:timestamp] || Time.now
139
+ market_time = options[:market_time] || timestamp
140
+
141
+ @kb.fact :stock, {
142
+ symbol: symbol,
143
+ price: price,
144
+ volume: volume,
145
+ timestamp: timestamp,
146
+ market_time: market_time,
147
+ market_session: determine_market_session(market_time),
148
+ price_change: options[:price_change] || 0,
149
+ gap_percentage: options[:gap_percentage] || 0
150
+ }
151
+ end
152
+
153
+ def add_price_tick(symbol, old_price, new_price, old_time, new_time)
154
+ price_delta = new_price - old_price
155
+ time_delta = new_time - old_time
156
+
157
+ @kb.fact :price_tick, {
158
+ symbol: symbol,
159
+ old_price: old_price,
160
+ new_price: new_price,
161
+ price_delta: price_delta,
162
+ time_delta: time_delta,
163
+ timestamp: new_time
164
+ }
165
+ end
166
+
167
+ def simulate_trading_day
168
+ puts "🏦 TIMESTAMPED STOCK TRADING SYSTEM"
169
+ puts "=" * 60
170
+
171
+ base_time = Time.parse("2024-08-15 09:30:00")
172
+
173
+ # Scenario 1: Market Open with Gap
174
+ puts "\n📊 SCENARIO 1: Market Open Gap Up"
175
+ puts "-" * 40
176
+ @kb.reset
177
+
178
+ add_timestamped_stock_fact("AAPL", 185.50, 2_500_000, {
179
+ market_time: base_time + 2*60, # 9:32 AM
180
+ price_change: 2.1,
181
+ gap_percentage: 2.3
182
+ })
183
+ @kb.run
184
+
185
+ # Scenario 2: Fresh Momentum Signal
186
+ puts "\n📊 SCENARIO 2: Fresh Momentum (Recent Data)"
187
+ puts "-" * 40
188
+ @kb.reset
189
+
190
+ add_timestamped_stock_fact("GOOGL", 142.80, 1_200_000, {
191
+ timestamp: Time.now - 30, # 30 seconds ago
192
+ market_time: Time.now - 30,
193
+ price_change: 3.2
194
+ })
195
+ @kb.run
196
+
197
+ # Scenario 3: Stale Data
198
+ puts "\n📊 SCENARIO 3: Stale Data Warning"
199
+ puts "-" * 40
200
+ @kb.reset
201
+
202
+ add_timestamped_stock_fact("TSLA", 195.40, 800_000, {
203
+ timestamp: Time.now - 600, # 10 minutes ago
204
+ market_time: Time.now - 600,
205
+ price_change: 1.5
206
+ })
207
+ @kb.run
208
+
209
+ # Scenario 4: After Hours Activity
210
+ puts "\n📊 SCENARIO 4: After Hours Trading"
211
+ puts "-" * 40
212
+ @kb.reset
213
+
214
+ after_hours_time = Time.parse("2024-08-15 17:30:00")
215
+ add_timestamped_stock_fact("NVDA", 425.80, 150_000, {
216
+ market_time: after_hours_time,
217
+ timestamp: after_hours_time
218
+ })
219
+ @kb.run
220
+
221
+ # Scenario 5: Rapid Price Movement
222
+ puts "\n📊 SCENARIO 5: Rapid Price Tick"
223
+ puts "-" * 40
224
+ @kb.reset
225
+
226
+ tick_time = Time.now
227
+ add_price_tick("META", 298.50, 299.25, tick_time - 3, tick_time)
228
+ @kb.run
229
+
230
+ # Scenario 6: End of Day
231
+ puts "\n📊 SCENARIO 6: End of Trading Day"
232
+ puts "-" * 40
233
+ @kb.reset
234
+
235
+ eod_time = Time.parse("2024-08-15 15:50:00")
236
+ add_timestamped_stock_fact("AMZN", 142.30, 900_000, {
237
+ market_time: eod_time,
238
+ timestamp: eod_time
239
+ })
240
+
241
+ @kb.fact :position, {
242
+ symbol: "AMZN",
243
+ status: "open",
244
+ shares: 100,
245
+ entry_price: 140.00,
246
+ unrealized_pnl: 230.00
247
+ }
248
+ @kb.run
249
+
250
+ puts "\n" + "=" * 60
251
+ puts "TIMESTAMPED TRADING SIMULATION COMPLETE"
252
+ end
253
+ end
254
+
255
+ if __FILE__ == $0
256
+ system = TimestampedTradingSystem.new
257
+ system.simulate_trading_day
258
+ end
@@ -4,7 +4,7 @@ require_relative '../lib/kbs'
4
4
 
5
5
  class TradingDemo
6
6
  def initialize
7
- @engine = KBS::ReteEngine.new
7
+ @engine = KBS::Engine.new
8
8
  setup_trading_rules
9
9
  puts "🏦 STOCK TRADING EXPERT SYSTEM LOADED"
10
10
  puts "📊 #{@engine.rules.size} trading strategies active"
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/kbs/dsl'
4
+ include KBS::DSL::ConditionHelpers
5
+
6
+ class TradingDemo
7
+ attr_reader :kb
8
+
9
+ def initialize
10
+ @kb = create_knowledge_base
11
+ puts "🏦 STOCK TRADING EXPERT SYSTEM LOADED"
12
+ puts "📊 #{@kb.rules.size} trading strategies active"
13
+ end
14
+
15
+ def create_knowledge_base
16
+ demo = self # Capture self for use in perform blocks
17
+ KBS.knowledge_base do
18
+ rule "golden_cross_buy" do
19
+ on :ma_signal, type: "golden_cross"
20
+ on :stock do
21
+ volume greater_than(500000)
22
+ end
23
+
24
+ perform do |facts, bindings|
25
+ stock = facts.find { |f| f.type == :stock }
26
+ signal = facts.find { |f| f.type == :ma_signal }
27
+ puts "📈 GOLDEN CROSS SIGNAL: #{stock[:symbol]}"
28
+ puts " 50-MA crossed above 200-MA"
29
+ puts " Volume: #{demo.format_volume(stock[:volume])}"
30
+ puts " Price: $#{stock[:price]}"
31
+ puts " Recommendation: STRONG BUY"
32
+ end
33
+ end
34
+
35
+ rule "momentum_breakout" do
36
+ on :stock do
37
+ price_change greater_than(2)
38
+ rsi between(50, 75)
39
+ end
40
+
41
+ perform do |facts, bindings|
42
+ stock = facts.find { |f| f.type == :stock }
43
+ puts "🚀 MOMENTUM BREAKOUT: #{stock[:symbol]}"
44
+ puts " Price Change: +#{stock[:price_change].round(1)}%"
45
+ puts " RSI: #{stock[:rsi].round(1)} (strong but not overbought)"
46
+ puts " Recommendation: BUY"
47
+ end
48
+ end
49
+
50
+ rule "oversold_reversal" do
51
+ on :stock do
52
+ rsi less_than(35)
53
+ end
54
+ on :market, trend: "bullish"
55
+
56
+ perform do |facts, bindings|
57
+ stock = facts.find { |f| f.type == :stock }
58
+ puts "🔄 OVERSOLD REVERSAL: #{stock[:symbol]}"
59
+ puts " RSI: #{stock[:rsi].round(1)} (oversold)"
60
+ puts " Market: Bullish environment"
61
+ puts " Recommendation: CONTRARIAN BUY"
62
+ end
63
+ end
64
+
65
+ rule "earnings_play" do
66
+ on :earnings do
67
+ days_until satisfies { |d| d <= 3 }
68
+ end
69
+ on :options do
70
+ iv greater_than(40)
71
+ end
72
+
73
+ perform do |facts, bindings|
74
+ earnings = facts.find { |f| f.type == :earnings }
75
+ options = facts.find { |f| f.type == :options }
76
+ puts "💰 EARNINGS PLAY: #{earnings[:symbol]}"
77
+ puts " Earnings in #{earnings[:days_until]} day(s)"
78
+ puts " Implied Volatility: #{options[:iv].round(1)}%"
79
+ puts " Recommendation: VOLATILITY STRATEGY"
80
+ end
81
+ end
82
+
83
+ rule "stop_loss_alert" do
84
+ on :position do
85
+ status "open"
86
+ loss_pct greater_than(8)
87
+ end
88
+
89
+ perform do |facts, bindings|
90
+ position = facts.find { |f| f.type == :position }
91
+ puts "🛑 STOP LOSS TRIGGERED: #{position[:symbol]}"
92
+ puts " Loss: #{position[:loss_pct].round(1)}%"
93
+ puts " Entry: $#{position[:entry_price]}"
94
+ puts " Current: $#{position[:current_price]}"
95
+ puts " Recommendation: SELL IMMEDIATELY"
96
+ end
97
+ end
98
+
99
+ rule "concentration_risk" do
100
+ on :portfolio do
101
+ concentration greater_than(25)
102
+ end
103
+
104
+ perform do |facts, bindings|
105
+ portfolio = facts.find { |f| f.type == :portfolio }
106
+ puts "⚠️ CONCENTRATION RISK: #{portfolio[:top_holding]}"
107
+ puts " Position Size: #{portfolio[:concentration].round(1)}% of portfolio"
108
+ puts " Recommendation: DIVERSIFY HOLDINGS"
109
+ end
110
+ end
111
+
112
+ rule "news_sentiment" do
113
+ on :news do
114
+ sentiment satisfies { |s| s.abs > 0.6 }
115
+ impact "high"
116
+ end
117
+
118
+ perform do |facts, bindings|
119
+ news = facts.find { |f| f.type == :news }
120
+ sentiment = news[:sentiment] > 0 ? "POSITIVE" : "NEGATIVE"
121
+ action = news[:sentiment] > 0 ? "BUY" : "SELL"
122
+ puts "📰 NEWS CATALYST: #{news[:symbol]}"
123
+ puts " Sentiment: #{sentiment} (#{news[:sentiment].round(2)})"
124
+ puts " Impact: HIGH"
125
+ puts " Recommendation: #{action} ON NEWS"
126
+ end
127
+ end
128
+
129
+ rule "sector_strength" do
130
+ on :sector do
131
+ performance greater_than(5)
132
+ trend "accelerating"
133
+ end
134
+
135
+ perform do |facts, bindings|
136
+ sector = facts.find { |f| f.type == :sector }
137
+ puts "🔄 SECTOR ROTATION: #{sector[:name]}"
138
+ puts " Performance: +#{sector[:performance].round(1)}%"
139
+ puts " Trend: Accelerating"
140
+ puts " Recommendation: INCREASE ALLOCATION"
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ def format_volume(volume)
147
+ if volume >= 1_000_000
148
+ "#{(volume / 1_000_000.0).round(1)}M"
149
+ elsif volume >= 1_000
150
+ "#{(volume / 1_000.0).round(1)}K"
151
+ else
152
+ volume.to_s
153
+ end
154
+ end
155
+
156
+ def generate_scenario(name, &block)
157
+ puts "\n" + "="*60
158
+ puts "SCENARIO: #{name}"
159
+ puts "="*60
160
+
161
+ @kb.reset
162
+
163
+ yield
164
+
165
+ puts "\nFacts in working memory:"
166
+ @kb.facts.each do |fact|
167
+ puts " #{fact}"
168
+ end
169
+ puts ""
170
+
171
+ @kb.run
172
+
173
+ puts "-"*60
174
+ end
175
+
176
+ def demo_scenarios
177
+ generate_scenario("Bull Market with Golden Cross") do
178
+ @kb.fact :stock, {
179
+ symbol: "AAPL",
180
+ price: 185.50,
181
+ volume: 1_250_000,
182
+ price_change: 1.2,
183
+ rsi: 65
184
+ }
185
+
186
+ @kb.fact :ma_signal, {
187
+ symbol: "AAPL",
188
+ type: "golden_cross"
189
+ }
190
+
191
+ @kb.fact :market, { trend: "bullish" }
192
+ end
193
+
194
+ generate_scenario("Momentum Breakout") do
195
+ @kb.fact :stock, {
196
+ symbol: "NVDA",
197
+ price: 425.80,
198
+ volume: 980_000,
199
+ price_change: 4.7,
200
+ rsi: 68
201
+ }
202
+
203
+ @kb.fact :market, { trend: "bullish" }
204
+ end
205
+
206
+ generate_scenario("Oversold Bounce Opportunity") do
207
+ @kb.fact :stock, {
208
+ symbol: "TSLA",
209
+ price: 178.90,
210
+ volume: 750_000,
211
+ price_change: -2.1,
212
+ rsi: 28
213
+ }
214
+
215
+ @kb.fact :market, { trend: "bullish" }
216
+ end
217
+
218
+ generate_scenario("Earnings Volatility Play") do
219
+ @kb.fact :earnings, {
220
+ symbol: "GOOGL",
221
+ days_until: 2,
222
+ expected_move: 8.5
223
+ }
224
+
225
+ @kb.fact :options, {
226
+ symbol: "GOOGL",
227
+ iv: 45.2,
228
+ iv_rank: 75
229
+ }
230
+ end
231
+
232
+ generate_scenario("Stop Loss Alert") do
233
+ @kb.fact :position, {
234
+ symbol: "META",
235
+ status: "open",
236
+ entry_price: 320.00,
237
+ current_price: 285.40,
238
+ loss_pct: 10.8,
239
+ shares: 100
240
+ }
241
+ end
242
+
243
+ generate_scenario("Portfolio Risk Warning") do
244
+ @kb.fact :portfolio, {
245
+ total_value: 250_000,
246
+ top_holding: "AAPL",
247
+ concentration: 32.5,
248
+ cash_pct: 5
249
+ }
250
+ end
251
+
252
+ generate_scenario("News-Driven Trade") do
253
+ @kb.fact :news, {
254
+ symbol: "MSFT",
255
+ sentiment: -0.75,
256
+ impact: "high",
257
+ headlines: "Major cloud outage affects services"
258
+ }
259
+
260
+ @kb.fact :stock, {
261
+ symbol: "MSFT",
262
+ price: 395.20,
263
+ price_change: -1.2,
264
+ volume: 890_000
265
+ }
266
+ end
267
+
268
+ generate_scenario("Sector Rotation Signal") do
269
+ @kb.fact :sector, {
270
+ name: "Technology",
271
+ performance: 7.3,
272
+ trend: "accelerating",
273
+ leaders: ["AAPL", "MSFT", "GOOGL"]
274
+ }
275
+ end
276
+
277
+ generate_scenario("Complex Multi-Signal Day") do
278
+ @kb.fact :stock, {
279
+ symbol: "AMZN",
280
+ price: 142.50,
281
+ volume: 1_800_000,
282
+ price_change: 3.8,
283
+ rsi: 72
284
+ }
285
+
286
+ @kb.fact :ma_signal, {
287
+ symbol: "AMZN",
288
+ type: "golden_cross"
289
+ }
290
+
291
+ @kb.fact :news, {
292
+ symbol: "AMZN",
293
+ sentiment: 0.8,
294
+ impact: "high",
295
+ headlines: "AWS wins major government contract"
296
+ }
297
+
298
+ @kb.fact :earnings, {
299
+ symbol: "AMZN",
300
+ days_until: 1,
301
+ expected_move: 6.2
302
+ }
303
+
304
+ @kb.fact :options, {
305
+ symbol: "AMZN",
306
+ iv: 52.1,
307
+ iv_rank: 85
308
+ }
309
+
310
+ @kb.fact :market, { trend: "bullish" }
311
+ end
312
+ end
313
+ end
314
+
315
+ if __FILE__ == $0
316
+ demo = TradingDemo.new
317
+ demo.demo_scenarios
318
+
319
+ puts "\n" + "="*60
320
+ puts "TRADING SYSTEM DEMONSTRATION COMPLETE"
321
+ puts "="*60
322
+ end
@@ -4,7 +4,7 @@ require_relative '../lib/kbs'
4
4
 
5
5
  class WorkingTradingDemo
6
6
  def initialize
7
- @engine = KBS::ReteEngine.new
7
+ @engine = KBS::Engine.new
8
8
  setup_simple_rules
9
9
  end
10
10