# Longport OpenAPI SDK for C++ `longport` provides an easy-to-use interface for invoking [`Longport OpenAPI`](https://open.longportapp.com/en/). ## Context Types | Context | Description | |---------|-------------| | `QuoteContext` | Real-time quotes, candlesticks, options, warrants, watchlists, push subscriptions | | `TradeContext` | Orders, positions, account balance, executions, cash flow | | `AssetContext` | Account statement download | | `ContentContext` | News, community topics | | `FundamentalContext` | Financial reports, analyst ratings, dividends, valuation, company overview, shareholders | | `MarketContext` | Market status, broker holdings, A/H premium, trade statistics, anomaly alerts, index constituents | | `CalendarContext` | Financial calendar (earnings, dividends, splits, IPOs, macro data, market closures) | | `PortfolioContext` | Exchange rates, portfolio P&L analysis | | `AlertContext` | Price alert management (add/enable/disable/delete) | | `DCAContext` | Dollar-cost averaging plan management | | `SharelistContext` | Community sharelist management | ## Documentation - SDK docs: https://longportapp.github.io/openapi/cpp/index.html - Longport OpenAPI: https://open.longportapp.com/en/ ## Examples Runnable examples live in `examples/cpp/`: - `examples/cpp/get_quote/main.cpp` - `examples/cpp/history_candlesticks_by_offset/main.cpp` - `examples/cpp/http_client/main.cpp` - `examples/cpp/subscribe_candlesticks/main.cpp` - `examples/cpp/subscribe_quote/main.cpp` - `examples/cpp/submit_order/main.cpp` - `examples/cpp/today_orders/main.cpp` ## Quickstart _Install Longport OpenAPI SDK_ [`Download C++ SDK`](https://github.com/longportapp/openapi/releases) ### Authentication Longport OpenAPI supports two authentication methods: #### 1. OAuth 2.0 (Recommended) OAuth 2.0 is the modern authentication method that uses Bearer tokens without requiring HMAC signatures. **Step 1: Register OAuth Client** First, register an OAuth client to get your `client_id`: _bash / macOS / Linux_ ```bash curl -X POST https://openapi.longportapp.com/oauth2/register \ -H "Content-Type: application/json" \ -d '{ "client_name": "My Application", "redirect_uris": ["http://localhost:60355/callback"], "grant_types": ["authorization_code", "refresh_token"] }' ``` _PowerShell (Windows)_ ```powershell Invoke-RestMethod -Method Post -Uri https://openapi.longportapp.com/oauth2/register ` -ContentType "application/json" ` -Body '{ "client_name": "My Application", "redirect_uris": ["http://localhost:60355/callback"], "grant_types": ["authorization_code", "refresh_token"] }' ``` Response: ```json { "client_id": "your-client-id-here", "client_secret": null, "client_name": "My Application", "redirect_uris": ["http://localhost:60355/callback"] } ``` Save the `client_id` for use in your application. **Step 2: Build OAuth client and create a Config** `OAuthBuilder::build` loads a cached token from `~/.longport/openapi/tokens/` (`%USERPROFILE%\.longport\openapi\tokens\` on Windows) if one exists and is still valid, or starts the browser authorization flow automatically. The token is persisted to the same path after a successful authorization or refresh. The resulting `OAuth` handle is passed directly to `Config::from_oauth`. ```c++ #include #include using namespace longport; int main(int argc, char const* argv[]) { OAuthBuilder("your-client-id") .build( [](const std::string& url) { std::cout << "Open this URL to authorize: " << url << std::endl; }, [](AsyncResult res) { if (!res) { std::cout << "OAuth failed: " << *res.status().message() << std::endl; return; } Config config = Config::from_oauth(*res); // Use config to create contexts... }); std::cin.get(); return 0; } ``` #### 2. Legacy API Key (Environment Variables) _Setting environment variables(MacOS/Linux)_ ```bash export LONGPORT_APP_KEY="App Key get from user center" export LONGPORT_APP_SECRET="App Secret get from user center" export LONGPORT_ACCESS_TOKEN="Access Token get from user center" ``` _Setting environment variables(Windows)_ ```powershell setx LONGPORT_APP_KEY "App Key get from user center" setx LONGPORT_APP_SECRET "App Secret get from user center" setx LONGPORT_ACCESS_TOKEN "Access Token get from user center" ``` ### Other environment variables | Name | Description | |----------------------------------|---------------------------------------------------------------------------------| | LONGPORT_LANGUAGE | Language identifier, `zh-CN`, `zh-HK` or `en` (Default: `en`) | | LONGPORT_HTTP_URL | HTTP endpoint url (Default: `https://openapi.longportapp.com`) | | LONGPORT_QUOTE_WS_URL | Quote websocket endpoint url (Default: `wss://openapi-quote.longportapp.com/v2`) | | LONGPORT_TRADE_WS_URL | Trade websocket endpoint url (Default: `wss://openapi-trade.longportapp.com/v2`) | | LONGPORT_ENABLE_OVERNIGHT | Enable overnight quote, `true` or `false` (Default: `false`) | | LONGPORT_PUSH_CANDLESTICK_MODE | `realtime` or `confirmed` (Default: `realtime`) | | LONGPORT_PRINT_QUOTE_PACKAGES | Print quote packages when connected, `true` or `false` (Default: `true`) | | LONGPORT_LOG_PATH | Set the path of the log files (Default: `no logs`) | ## Quote API _(Get basic information of securities)_ ```c++ #include #include #ifdef WIN32 #include #endif using namespace longport; using namespace longport::quote; int main(int argc, char const* argv[]) { #ifdef WIN32 SetConsoleOutputCP(CP_UTF8); #endif OAuthBuilder("your-client-id") .build( [](const std::string& url) { std::cout << "Open this URL to authorize: " << url << std::endl; }, [](AsyncResult res) { if (!res) { std::cout << "OAuth failed: " << *res.status().message() << std::endl; return; } Config config = Config::from_oauth(*res); QuoteContext ctx = QuoteContext::create(config); std::vector symbols = { "700.HK", "AAPL.US", "TSLA.US", "NFLX.US" }; ctx.quote(symbols, [](auto res) { if (!res) { std::cout << "failed to get quote: " << *res.status().message() << std::endl; return; } for (auto it = res->cbegin(); it != res->cend(); ++it) { std::cout << it->symbol << " timestamp=" << it->timestamp << " last_done=" << (double)it->last_done << " prev_close=" << (double)it->prev_close << " open=" << (double)it->open << " high=" << (double)it->high << " low=" << (double)it->low << " volume=" << it->volume << " turnover=" << it->turnover << std::endl; } }); }); std::cin.get(); return 0; } ``` ## Quote API _(Subscribe quotes)_ ```c++ #include #include #ifdef WIN32 #include #endif using namespace longport; using namespace longport::quote; int main(int argc, char const* argv[]) { #ifdef WIN32 SetConsoleOutputCP(CP_UTF8); #endif OAuthBuilder("your-client-id") .build( [](const std::string& url) { std::cout << "Open this URL to authorize: " << url << std::endl; }, [](AsyncResult res) { if (!res) { std::cout << "OAuth failed: " << *res.status().message() << std::endl; return; } Config config = Config::from_oauth(*res); QuoteContext ctx = QuoteContext::create(config); ctx.set_on_quote([](auto event) { std::cout << event->symbol << " timestamp=" << event->timestamp << " last_done=" << (double)event->last_done << " open=" << (double)event->open << " high=" << (double)event->high << " low=" << (double)event->low << " volume=" << event->volume << " turnover=" << event->turnover << std::endl; }); std::vector symbols = { "700.HK", "AAPL.US", "TSLA.US", "NFLX.US" }; ctx.subscribe(symbols, SubFlags::QUOTE(), [](auto res) { if (!res) { std::cout << "failed to subscribe: " << *res.status().message() << std::endl; } }); }); std::cin.get(); return 0; } ``` ## Trade API _(Submit order)_ ```c++ #include #include #ifdef WIN32 #include #endif using namespace longport; using namespace longport::trade; int main(int argc, char const* argv[]) { #ifdef WIN32 SetConsoleOutputCP(CP_UTF8); #endif OAuthBuilder("your-client-id") .build( [](const std::string& url) { std::cout << "Open this URL to authorize: " << url << std::endl; }, [](AsyncResult res) { if (!res) { std::cout << "OAuth failed: " << *res.status().message() << std::endl; return; } Config config = Config::from_oauth(*res); TradeContext ctx = TradeContext::create(config); SubmitOrderOptions opts{ "700.HK", OrderType::LO, OrderSide::Buy, Decimal(200), TimeInForceType::Day, Decimal(50.0), std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, }; ctx.submit_order(opts, [](auto res) { if (!res) { std::cout << "failed to submit order: " << *res.status().message() << std::endl; return; } std::cout << "order id: " << res->order_id << std::endl; }); }); std::cin.get(); return 0; } ``` ## Troubleshooting - Windows `setx` requires a new terminal; use `set` for the current `cmd.exe` session. - If you don't see push events, keep the process alive (examples use `std::cin.get()`). - If building on Linux/macOS, ensure `ncurses` is installed (examples link it on non-Windows). - For debugging, set `LONGPORT_LOG_PATH` to enable SDK logs. ## License Licensed under either of * Apache License, Version 2.0,([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option.