Class: GrowwMcp::Client
- Inherits:
-
Object
- Object
- GrowwMcp::Client
- Defined in:
- lib/groww_mcp/client.rb
Constant Summary collapse
- BASE_URL =
"https://api.groww.in"- MAX_RETRIES =
3- RETRY_DELAY =
0.5- INSTRUMENTS_CACHE_PATH =
File.join(Dir.tmpdir, "groww-mcp-instruments.csv")
- INSTRUMENTS_CACHE_TTL =
24 hours
24 * 60 * 60
Instance Method Summary collapse
-
#calculate_margin(orders, segment:) ⇒ Object
Margin requirement for a basket of orders.
- #cancel_order(order_id, segment: "CASH") ⇒ Object
- #cancel_smart_order(smart_order_id, smart_order_type:, segment: "CASH") ⇒ Object
- #create_smart_order(order) ⇒ Object
- #download_instruments ⇒ Object
-
#greeks(trading_symbol:, underlying:, expiry:, exchange: "NSE") ⇒ Object
Greeks (requires ₹499/mo subscription) ===.
-
#historical_candles(trading_symbol, start_time, end_time, exchange: "NSE", segment: "CASH", interval_in_minutes: nil) ⇒ Object
Historical Data (requires ₹499/mo subscription) ===.
-
#holdings ⇒ Object
Portfolio ===.
-
#initialize(auth) ⇒ Client
constructor
A new instance of Client.
-
#instrument_detail(trading_symbol, exchange: "NSE", segment: "CASH") ⇒ Object
Exact trading-symbol match (case-insensitive), filtered by exchange/segment.
- #ltp(symbols, exchange: "NSE", segment: "CASH") ⇒ Object
- #margins ⇒ Object
- #modify_order(order_id, modifications) ⇒ Object
- #modify_smart_order(smart_order_id, smart_order_type:, segment:, modifications: {}) ⇒ Object
- #ohlc(symbols, exchange: "NSE", segment: "CASH") ⇒ Object
-
#option_chain(underlying, expiry_date:, exchange: "NSE") ⇒ Object
Option Chain (requires ₹499/mo subscription) ===.
- #order_detail(order_id, segment: "CASH") ⇒ Object
-
#order_list(segment: nil, page: nil, page_size: nil) ⇒ Object
Orders ===.
- #order_trades(order_id, segment: "CASH") ⇒ Object
- #place_order(order) ⇒ Object
- #positions(segment: nil) ⇒ Object
-
#profile ⇒ Object
User ===.
-
#quote(trading_symbol, exchange: "NSE", segment: "CASH") ⇒ Object
Live Data (requires ₹499/mo subscription) ===.
-
#search_instruments(query, limit: 20) ⇒ Object
Case-insensitive substring search on trading symbol and name.
-
#smart_order_list(smart_order_type: nil, page: nil, page_size: nil) ⇒ Object
Smart Orders (GTT/OCO) ===.
Constructor Details
#initialize(auth) ⇒ Client
Returns a new instance of Client.
17 18 19 |
# File 'lib/groww_mcp/client.rb', line 17 def initialize(auth) @auth = auth end |
Instance Method Details
#calculate_margin(orders, segment:) ⇒ Object
Margin requirement for a basket of orders. Body is a JSON ARRAY of order objects; segment goes as a query param.
191 192 193 |
# File 'lib/groww_mcp/client.rb', line 191 def calculate_margin(orders, segment:) post("/v1/margins/detail/orders", orders, params: { segment: segment }) end |
#cancel_order(order_id, segment: "CASH") ⇒ Object
61 62 63 |
# File 'lib/groww_mcp/client.rb', line 61 def cancel_order(order_id, segment: "CASH") post("/v1/order/cancel", groww_order_id: order_id, segment: segment) end |
#cancel_smart_order(smart_order_id, smart_order_type:, segment: "CASH") ⇒ Object
89 90 91 |
# File 'lib/groww_mcp/client.rb', line 89 def cancel_smart_order(smart_order_id, smart_order_type:, segment: "CASH") post("/v1/order-advance/cancel/#{segment}/#{smart_order_type}/#{smart_order_id}", {}) end |
#create_smart_order(order) ⇒ Object
79 80 81 82 |
# File 'lib/groww_mcp/client.rb', line 79 def create_smart_order(order) order = { reference_id: generate_reference_id }.merge(order) post("/v1/order-advance/create", order) end |
#download_instruments ⇒ Object
173 174 175 176 177 178 179 |
# File 'lib/groww_mcp/client.rb', line 173 def download_instruments uri = URI("https://growwapi-assets.groww.in/instruments/instrument.csv") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true response = http.request(Net::HTTP::Get.new(uri)) response.body end |
#greeks(trading_symbol:, underlying:, expiry:, exchange: "NSE") ⇒ Object
Greeks (requires ₹499/mo subscription) ===
115 116 117 118 |
# File 'lib/groww_mcp/client.rb', line 115 def greeks(trading_symbol:, underlying:, expiry:, exchange: "NSE") get("/v1/live-data/greeks/exchange/#{exchange}/underlying/#{}" \ "/trading_symbol/#{trading_symbol}/expiry/#{expiry}") end |
#historical_candles(trading_symbol, start_time, end_time, exchange: "NSE", segment: "CASH", interval_in_minutes: nil) ⇒ Object
Historical Data (requires ₹499/mo subscription) ===
122 123 124 125 126 127 128 129 130 |
# File 'lib/groww_mcp/client.rb', line 122 def historical_candles(trading_symbol, start_time, end_time, exchange: "NSE", segment: "CASH", interval_in_minutes: nil) params = { trading_symbol: trading_symbol, exchange: exchange, segment: segment, start_time: normalize_time(start_time), end_time: normalize_time(end_time), } params[:interval_in_minutes] = interval_in_minutes if interval_in_minutes get("/v1/historical/candle/range", params) end |
#holdings ⇒ Object
Portfolio ===
23 24 25 |
# File 'lib/groww_mcp/client.rb', line 23 def holdings get("/v1/holdings/user") end |
#instrument_detail(trading_symbol, exchange: "NSE", segment: "CASH") ⇒ Object
Exact trading-symbol match (case-insensitive), filtered by exchange/segment. Returns the matching row as a Hash, or nil if not found.
162 163 164 165 166 167 168 169 170 171 |
# File 'lib/groww_mcp/client.rb', line 162 def instrument_detail(trading_symbol, exchange: "NSE", segment: "CASH") instruments.each do |row| next unless row["trading_symbol"].to_s.casecmp?(trading_symbol.to_s) next if exchange && !row["exchange"].to_s.empty? && !row["exchange"].casecmp?(exchange.to_s) next if segment && !row["segment"].to_s.empty? && !row["segment"].casecmp?(segment.to_s) return row.to_h end nil end |
#ltp(symbols, exchange: "NSE", segment: "CASH") ⇒ Object
99 100 101 |
# File 'lib/groww_mcp/client.rb', line 99 def ltp(symbols, exchange: "NSE", segment: "CASH") get("/v1/live-data/ltp", segment: segment, exchange_symbols: exchange_symbols(symbols, exchange)) end |
#margins ⇒ Object
33 34 35 |
# File 'lib/groww_mcp/client.rb', line 33 def margins get("/v1/margins/detail/user") end |
#modify_order(order_id, modifications) ⇒ Object
57 58 59 |
# File 'lib/groww_mcp/client.rb', line 57 def modify_order(order_id, modifications) post("/v1/order/modify", modifications.merge(groww_order_id: order_id)) end |
#modify_smart_order(smart_order_id, smart_order_type:, segment:, modifications: {}) ⇒ Object
84 85 86 87 |
# File 'lib/groww_mcp/client.rb', line 84 def modify_smart_order(smart_order_id, smart_order_type:, segment:, modifications: {}) put("/v1/order-advance/modify/#{smart_order_id}", modifications.merge(smart_order_type: smart_order_type, segment: segment)) end |
#ohlc(symbols, exchange: "NSE", segment: "CASH") ⇒ Object
103 104 105 |
# File 'lib/groww_mcp/client.rb', line 103 def ohlc(symbols, exchange: "NSE", segment: "CASH") get("/v1/live-data/ohlc", segment: segment, exchange_symbols: exchange_symbols(symbols, exchange)) end |
#option_chain(underlying, expiry_date:, exchange: "NSE") ⇒ Object
Option Chain (requires ₹499/mo subscription) ===
109 110 111 |
# File 'lib/groww_mcp/client.rb', line 109 def option_chain(, expiry_date:, exchange: "NSE") get("/v1/option-chain/exchange/#{exchange}/underlying/#{}", expiry_date: expiry_date) end |
#order_detail(order_id, segment: "CASH") ⇒ Object
47 48 49 |
# File 'lib/groww_mcp/client.rb', line 47 def order_detail(order_id, segment: "CASH") get("/v1/order/detail/#{order_id}", segment: segment) end |
#order_list(segment: nil, page: nil, page_size: nil) ⇒ Object
Orders ===
39 40 41 42 43 44 45 |
# File 'lib/groww_mcp/client.rb', line 39 def order_list(segment: nil, page: nil, page_size: nil) params = {} params[:segment] = segment if segment params[:page] = page if page params[:page_size] = page_size if page_size get("/v1/order/list", params) end |
#order_trades(order_id, segment: "CASH") ⇒ Object
65 66 67 |
# File 'lib/groww_mcp/client.rb', line 65 def order_trades(order_id, segment: "CASH") get("/v1/order/trades/#{order_id}", segment: segment) end |
#place_order(order) ⇒ Object
51 52 53 54 55 |
# File 'lib/groww_mcp/client.rb', line 51 def place_order(order) # reference_id lets Groww dedupe if the same order is ever re-submitted order = { order_reference_id: generate_reference_id }.merge(order) post("/v1/order/create", order) end |
#positions(segment: nil) ⇒ Object
27 28 29 30 31 |
# File 'lib/groww_mcp/client.rb', line 27 def positions(segment: nil) path = "/v1/positions/user" path += "?segment=#{segment}" if segment get(path) end |
#profile ⇒ Object
User ===
183 184 185 |
# File 'lib/groww_mcp/client.rb', line 183 def profile get("/v1/user/detail") end |
#quote(trading_symbol, exchange: "NSE", segment: "CASH") ⇒ Object
Live Data (requires ₹499/mo subscription) ===
95 96 97 |
# File 'lib/groww_mcp/client.rb', line 95 def quote(trading_symbol, exchange: "NSE", segment: "CASH") get("/v1/live-data/quote", trading_symbol: trading_symbol, exchange: exchange, segment: segment) end |
#search_instruments(query, limit: 20) ⇒ Object
Case-insensitive substring search on trading symbol and name. Runs entirely locally against the cached instruments CSV — no API call, no Live Data subscription needed.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/groww_mcp/client.rb', line 137 def search_instruments(query, limit: 20) q = query.to_s.downcase return [] if q.empty? matches = [] instruments.each do |row| symbol = row["trading_symbol"].to_s.downcase name = row["name"].to_s.downcase matches << row if symbol.include?(q) || name.include?(q) end # Rank so the most useful rows surface first: exact symbol match, # then CASH (equity) before FNO contracts, then symbol-prefix matches. matches.sort_by! do |row| symbol = row["trading_symbol"].to_s.downcase [symbol == q ? 0 : 1, row["segment"] == "CASH" ? 0 : 1, symbol.start_with?(q) ? 0 : 1, symbol] end matches.first(limit).map(&:to_h) end |
#smart_order_list(smart_order_type: nil, page: nil, page_size: nil) ⇒ Object
Smart Orders (GTT/OCO) ===
71 72 73 74 75 76 77 |
# File 'lib/groww_mcp/client.rb', line 71 def smart_order_list(smart_order_type: nil, page: nil, page_size: nil) params = {} params[:smart_order_type] = smart_order_type if smart_order_type params[:page] = page if page params[:page_size] = page_size if page_size get("/v1/order-advance/list", params) end |