diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..ac2e380
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,48 @@
+name: Docs
+
+on:
+ push:
+ branches: [main]
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: false
+
+jobs:
+ build-docs:
+ name: Build documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: astral-sh/setup-uv@v4
+ with:
+ enable-cache: true
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+
+ - run: uv sync --frozen --extra docs
+
+ - run: uv run sphinx-build -b html docs/ docs/_build/html
+
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs/_build/html
+
+ deploy:
+ name: Deploy to GitHub Pages
+ needs: build-docs
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index e7345ae..d560b7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,6 @@ coverage.xml
.mypy_cache/
.ruff_cache/
+# Sphinx documentation
+docs/_build/
+
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..08835bd
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,19 @@
+# Minimal makefile for Sphinx documentation
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/api/client.rst b/docs/api/client.rst
new file mode 100644
index 0000000..827cbb5
--- /dev/null
+++ b/docs/api/client.rst
@@ -0,0 +1,32 @@
+Client
+======
+
+The main entry point for the SDK. :class:`~etoropy.EToroTrading` wraps REST
+endpoints, WebSocket streaming, and instrument resolution behind a single
+async interface.
+
+EToroTrading
+------------
+
+.. autoclass:: etoropy.EToroTrading
+ :members:
+ :show-inheritance:
+
+OrderOptions
+------------
+
+.. autoclass:: etoropy.OrderOptions
+ :members:
+
+InstrumentResolver
+------------------
+
+.. autoclass:: etoropy.InstrumentResolver
+ :members:
+ :show-inheritance:
+
+InstrumentInfo
+--------------
+
+.. autoclass:: etoropy.InstrumentInfo
+ :members:
diff --git a/docs/api/config.rst b/docs/api/config.rst
new file mode 100644
index 0000000..c02b176
--- /dev/null
+++ b/docs/api/config.rst
@@ -0,0 +1,6 @@
+Configuration
+=============
+
+.. autopydantic_settings:: etoropy.EToroConfig
+ :members:
+ :show-inheritance:
diff --git a/docs/api/errors.rst b/docs/api/errors.rst
new file mode 100644
index 0000000..df07d1b
--- /dev/null
+++ b/docs/api/errors.rst
@@ -0,0 +1,55 @@
+Errors
+======
+
+All SDK errors inherit from :class:`~etoropy.EToroError`:
+
+.. code-block:: text
+
+ EToroError
+ +-- EToroApiError # HTTP 4xx/5xx
+ | +-- EToroRateLimitError # HTTP 429
+ +-- EToroAuthError # HTTP 401/403 or WS auth failure
+ +-- EToroValidationError # Invalid input
+ +-- EToroWebSocketError # WS connection/protocol errors
+
+EToroError
+----------
+
+.. autoclass:: etoropy.EToroError
+ :members:
+ :show-inheritance:
+
+EToroApiError
+-------------
+
+.. autoclass:: etoropy.EToroApiError
+ :members:
+ :show-inheritance:
+
+EToroRateLimitError
+-------------------
+
+.. autoclass:: etoropy.EToroRateLimitError
+ :members:
+ :show-inheritance:
+
+EToroAuthError
+--------------
+
+.. autoclass:: etoropy.EToroAuthError
+ :members:
+ :show-inheritance:
+
+EToroValidationError
+--------------------
+
+.. autoclass:: etoropy.EToroValidationError
+ :members:
+ :show-inheritance:
+
+EToroWebSocketError
+-------------------
+
+.. autoclass:: etoropy.EToroWebSocketError
+ :members:
+ :show-inheritance:
diff --git a/docs/api/http.rst b/docs/api/http.rst
new file mode 100644
index 0000000..b311f5d
--- /dev/null
+++ b/docs/api/http.rst
@@ -0,0 +1,36 @@
+HTTP Layer
+==========
+
+Low-level HTTP transport with rate limiting and retry logic.
+
+HttpClient
+----------
+
+.. autoclass:: etoropy.HttpClient
+ :members:
+ :show-inheritance:
+
+RequestOptions
+--------------
+
+.. autoclass:: etoropy.RequestOptions
+ :members:
+
+RateLimiter
+-----------
+
+.. autoclass:: etoropy.RateLimiter
+ :members:
+ :show-inheritance:
+
+RateLimiterOptions
+------------------
+
+.. autoclass:: etoropy.RateLimiterOptions
+ :members:
+
+RetryOptions
+------------
+
+.. autoclass:: etoropy.http.RetryOptions
+ :members:
diff --git a/docs/api/index.rst b/docs/api/index.rst
new file mode 100644
index 0000000..73201b1
--- /dev/null
+++ b/docs/api/index.rst
@@ -0,0 +1,13 @@
+API Reference
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ client
+ config
+ models
+ rest
+ websocket
+ http
+ errors
diff --git a/docs/api/models.rst b/docs/api/models.rst
new file mode 100644
index 0000000..1cabfcb
--- /dev/null
+++ b/docs/api/models.rst
@@ -0,0 +1,47 @@
+Models
+======
+
+All data models are `Pydantic v2 `_
+``BaseModel`` subclasses with full type annotations.
+
+Enums
+-----
+
+.. automodule:: etoropy.models.enums
+ :members:
+ :show-inheritance:
+
+Common
+------
+
+.. automodule:: etoropy.models.common
+ :members:
+ :show-inheritance:
+
+Market Data
+-----------
+
+.. automodule:: etoropy.models.market_data
+ :members:
+ :show-inheritance:
+
+Trading
+-------
+
+.. automodule:: etoropy.models.trading
+ :members:
+ :show-inheritance:
+
+Feeds & Social
+--------------
+
+.. automodule:: etoropy.models.feeds
+ :members:
+ :show-inheritance:
+
+WebSocket Messages
+------------------
+
+.. automodule:: etoropy.models.websocket
+ :members:
+ :show-inheritance:
diff --git a/docs/api/rest.rst b/docs/api/rest.rst
new file mode 100644
index 0000000..0fef651
--- /dev/null
+++ b/docs/api/rest.rst
@@ -0,0 +1,75 @@
+REST Clients
+============
+
+The :class:`~etoropy.RestClient` facade composes nine specialized sub-clients,
+one per API domain.
+
+RestClient
+----------
+
+.. autoclass:: etoropy.RestClient
+ :members:
+ :show-inheritance:
+
+MarketDataClient
+----------------
+
+.. autoclass:: etoropy.MarketDataClient
+ :members:
+ :show-inheritance:
+
+TradingExecutionClient
+----------------------
+
+.. autoclass:: etoropy.TradingExecutionClient
+ :members:
+ :show-inheritance:
+
+TradingInfoClient
+-----------------
+
+.. autoclass:: etoropy.TradingInfoClient
+ :members:
+ :show-inheritance:
+
+WatchlistsClient
+----------------
+
+.. autoclass:: etoropy.WatchlistsClient
+ :members:
+ :show-inheritance:
+
+FeedsClient
+-----------
+
+.. autoclass:: etoropy.FeedsClient
+ :members:
+ :show-inheritance:
+
+ReactionsClient
+---------------
+
+.. autoclass:: etoropy.ReactionsClient
+ :members:
+ :show-inheritance:
+
+DiscoveryClient
+---------------
+
+.. autoclass:: etoropy.DiscoveryClient
+ :members:
+ :show-inheritance:
+
+UsersInfoClient
+---------------
+
+.. autoclass:: etoropy.UsersInfoClient
+ :members:
+ :show-inheritance:
+
+PiDataClient
+-------------
+
+.. autoclass:: etoropy.PiDataClient
+ :members:
+ :show-inheritance:
diff --git a/docs/api/websocket.rst b/docs/api/websocket.rst
new file mode 100644
index 0000000..d2dc4c7
--- /dev/null
+++ b/docs/api/websocket.rst
@@ -0,0 +1,31 @@
+WebSocket
+=========
+
+Real-time streaming via the eToro WebSocket API.
+
+WsClient
+--------
+
+.. autoclass:: etoropy.WsClient
+ :members:
+ :show-inheritance:
+
+WsClientOptions
+---------------
+
+.. autoclass:: etoropy.WsClientOptions
+ :members:
+
+Message Parser
+--------------
+
+.. automodule:: etoropy.ws.message_parser
+ :members:
+ :show-inheritance:
+
+Subscription Tracker
+--------------------
+
+.. autoclass:: etoropy.ws.WsSubscriptionTracker
+ :members:
+ :show-inheritance:
diff --git a/docs/architecture.rst b/docs/architecture.rst
new file mode 100644
index 0000000..b43f741
--- /dev/null
+++ b/docs/architecture.rst
@@ -0,0 +1,179 @@
+Architecture
+============
+
+etoropy is organized in layers. The high-level
+:class:`~etoropy.EToroTrading` client composes REST, WebSocket, and
+instrument-resolution sub-systems and exposes a unified async API.
+
+Layer diagram
+-------------
+
+.. code-block:: text
+
+ +------------------------------------------------------+
+ | EToroTrading (trading/client.py) |
+ | High-level: buy, sell, stream, wait_for_order |
+ +----+-----------------------------+-------------------+
+ | |
+ +----v-------------+ +-----------v-----------+
+ | RestClient | | WsClient |
+ | (9 sub-clients) | | auth, heartbeat, |
+ | | | reconnect, events |
+ +----+-------------+ +-----------+-----------+
+ | |
+ +----v-------------+ +-----------v-----------+
+ | HttpClient | | websockets lib |
+ | httpx + retry | | (ping_interval for |
+ | + rate limiter | | heartbeat) |
+ +------------------+ +-----------------------+
+
+Package layout
+--------------
+
+.. code-block:: text
+
+ etoropy/
+ __init__.py # Public API exports
+ _utils.py # UUID generation
+ config/
+ settings.py # EToroConfig (pydantic-settings)
+ constants.py # URLs, defaults, limits
+ errors/
+ exceptions.py # 6-class error hierarchy
+ models/
+ enums.py # CandleInterval, OrderStatusId, etc.
+ common.py # Pagination, TokenResponse
+ market_data.py # Instrument, Rate, Candle models
+ trading.py # Order, Position, Portfolio models
+ feeds.py # Social feed, user profile models
+ websocket.py # WsEnvelope, WsInstrumentRate, WsPrivateEvent
+ http/
+ client.py # HttpClient (httpx wrapper with auth, retry, rate limiting)
+ rate_limiter.py # Token-bucket rate limiter
+ retry.py # Exponential backoff with jitter
+ rest/
+ _base.py # BaseRestClient (GET/POST/PUT/DELETE helpers)
+ rest_client.py # RestClient facade (composes all sub-clients)
+ market_data.py # 8 endpoints
+ trading_execution.py # 7 endpoints (demo/real routing)
+ trading_info.py # 4 endpoints (demo/real routing)
+ watchlists.py # 14 endpoints
+ feeds.py # 3 endpoints
+ reactions.py # 1 endpoint
+ discovery.py # 2 endpoints
+ pi_data.py # 1 endpoint
+ users_info.py # 6 endpoints
+ ws/
+ client.py # WsClient (auth, heartbeat, reconnect, events)
+ message_parser.py # Parse WS envelopes into typed events
+ subscription.py # Topic set tracking for reconnect re-subscribe
+ trading/
+ client.py # EToroTrading (high-level entry point)
+ instrument_resolver.py # Symbol <-> ID resolution (CSV + API)
+ data/
+ instruments.csv # 5,200+ symbol mappings
+
+REST sub-clients
+----------------
+
+The :class:`~etoropy.RestClient` facade composes nine specialized clients:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 10 60
+
+ * - Client
+ - Endpoints
+ - Description
+ * - :class:`~etoropy.MarketDataClient`
+ - 8
+ - Instruments, rates, candles, exchanges, industries
+ * - :class:`~etoropy.TradingExecutionClient`
+ - 7
+ - Market/limit orders, close positions, cancel orders
+ * - :class:`~etoropy.TradingInfoClient`
+ - 4
+ - Portfolio, P&L, order status, trade history
+ * - :class:`~etoropy.WatchlistsClient`
+ - 14
+ - CRUD for user/public watchlists
+ * - :class:`~etoropy.FeedsClient`
+ - 3
+ - Instrument/user feeds, post creation
+ * - :class:`~etoropy.ReactionsClient`
+ - 1
+ - Comment creation
+ * - :class:`~etoropy.DiscoveryClient`
+ - 2
+ - Curated lists, market recommendations
+ * - :class:`~etoropy.UsersInfoClient`
+ - 6
+ - User profiles, portfolios, performance, search
+ * - :class:`~etoropy.PiDataClient`
+ - 1
+ - Copier public info
+
+WebSocket event system
+----------------------
+
+:class:`~etoropy.EToroTrading` exposes a Node.js-style event emitter:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 35 45
+
+ * - Event
+ - Callback signature
+ - Description
+ * - ``"price"``
+ - ``(symbol, instrument_id, WsInstrumentRate)``
+ - Live price tick
+ * - ``"order:update"``
+ - ``(WsPrivateEvent)``
+ - Order status change
+ * - ``"connected"``
+ - ``()``
+ - WebSocket connected and authenticated
+ * - ``"disconnected"``
+ - ``()``
+ - Client disconnected
+ * - ``"error"``
+ - ``(Exception)``
+ - Any error
+ * - ``"ws:message"``
+ - ``(WsEnvelope)``
+ - Raw WebSocket envelope
+
+Register handlers with :meth:`~etoropy.EToroTrading.on`,
+:meth:`~etoropy.EToroTrading.off`, and
+:meth:`~etoropy.EToroTrading.once`.
+
+Instrument resolution
+---------------------
+
+The :class:`~etoropy.InstrumentResolver` translates human-readable symbols
+(``"AAPL"``, ``"BTC"``) into eToro's integer instrument IDs through three
+tiers:
+
+1. **Bundled CSV** -- 5,200+ pre-mapped symbols loaded with
+ ``load_bundled_csv()``. Instant, no network call.
+2. **API exact match** -- queries ``/market-data/search`` by
+ ``internalSymbolFull``.
+3. **API text search** -- fallback free-text search on the same endpoint.
+
+Results are cached in memory for the lifetime of the client.
+
+Rate limiting & retry
+---------------------
+
+**Rate limiter**: Token-bucket algorithm (20 requests per 10-second window by
+default). Automatically pauses outgoing requests when the bucket is full.
+Honors ``Retry-After`` headers from 429 responses.
+
+**Retry**: Exponential backoff with jitter (+-25%). Retries on:
+
+- HTTP 429 (rate limit)
+- HTTP 5xx (server error)
+- Connection errors and read timeouts
+
+Default: 3 attempts, 1-second base delay, 2x backoff multiplier.
diff --git a/docs/changelog.rst b/docs/changelog.rst
new file mode 100644
index 0000000..e2a2d56
--- /dev/null
+++ b/docs/changelog.rst
@@ -0,0 +1,23 @@
+Changelog
+=========
+
+v0.1.1 (2026-02-26)
+--------------------
+
+- Add Sphinx documentation site with Furo theme and autodoc API reference
+- Add quickstart, architecture, and examples guides
+- Add GitHub Actions workflow for automatic docs deploy to GitHub Pages
+
+v0.1.0 (2025)
+--------------
+
+Initial release.
+
+- 42+ REST endpoints across 9 sub-clients (market data, trading execution,
+ trading info, watchlists, feeds, reactions, discovery, user info, PI data)
+- Real-time WebSocket streaming with auto-reconnect and heartbeat
+- :class:`~etoropy.EToroTrading` high-level client with event emitter
+- :class:`~etoropy.InstrumentResolver` with bundled 5,200+ symbol CSV
+- Token-bucket rate limiter and exponential-backoff retry
+- Full type hints (mypy strict) and Pydantic v2 models
+- Demo and real trading mode support
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..8f2f5cb
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,75 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+import importlib.metadata
+
+# -- Project information -----------------------------------------------------
+
+project = "etoropy"
+copyright = "2025, Massimo Gollo"
+author = "Massimo Gollo"
+release = importlib.metadata.version("etoropy")
+version = ".".join(release.split(".")[:2])
+
+# -- General configuration ---------------------------------------------------
+
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.viewcode",
+ "sphinx_autodoc_typehints",
+ "sphinx_copybutton",
+ "sphinxcontrib.autodoc_pydantic",
+]
+
+templates_path = ["_templates"]
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
+
+# -- Options for HTML output -------------------------------------------------
+
+html_theme = "furo"
+html_title = "etoropy"
+html_static_path = []
+
+# -- autodoc -----------------------------------------------------------------
+
+autodoc_default_options = {
+ "members": True,
+ "show-inheritance": True,
+ "undoc-members": False,
+}
+autodoc_member_order = "bysource"
+autodoc_typehints = "description"
+
+# -- sphinx-autodoc-typehints ------------------------------------------------
+
+always_document_param_types = True
+typehints_defaults = "braces"
+
+# -- autodoc-pydantic --------------------------------------------------------
+
+autodoc_pydantic_model_show_json = False
+autodoc_pydantic_model_show_config_summary = False
+autodoc_pydantic_model_show_field_summary = True
+autodoc_pydantic_model_show_validator_summary = True
+autodoc_pydantic_field_list_validators = True
+autodoc_pydantic_settings_show_json = False
+autodoc_pydantic_settings_show_config_summary = False
+autodoc_pydantic_settings_show_field_summary = True
+
+# -- intersphinx -------------------------------------------------------------
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3", None),
+ "pydantic": ("https://docs.pydantic.dev/latest/", None),
+}
+
+suppress_warnings = ["sphinx_autodoc_typehints.forward_reference"]
+
+# -- copybutton --------------------------------------------------------------
+
+copybutton_prompt_text = r">>> |\.\.\. |\$ "
+copybutton_prompt_is_regexp = True
diff --git a/docs/examples.rst b/docs/examples.rst
new file mode 100644
index 0000000..4df95aa
--- /dev/null
+++ b/docs/examples.rst
@@ -0,0 +1,126 @@
+Examples
+========
+
+The examples below are taken from the ``examples/`` directory in the
+repository. Each is a standalone script that you can run with:
+
+.. code-block:: bash
+
+ uv run python examples/