We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
NaN values on /status
<!-- 
Have you searched for similar issues before posting it?

If you have discovered a bug in the bot, please [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). 
If it hasn't been reported, please create a new issue.

Please do not use bug reports to request new features.
-->

## Describe your environment

  * Operating system: Raspbian
  * Python Version: 3.9.9 (`python -V`)
  * CCXT version: 1.80.61 (`pip freeze | grep ccxt`)
  * Freqtrade Version: docker-44000ae0 (`freqtrade -V` or `docker-compose run --rm freqtrade -V` for Freqtrade running in docker)
  
Note: All issues other than enhancement requests will be closed without further comment if the above template is deleted or not filled out.

## Describe the problem:

*Explain the problem you have encountered*

### Steps to reproduce:

  1. Open FreqUI
  2. Go to Dashboard
  
### Observed Results:

Due to the API sending "NaN" as values, the frontend can't parse the JSON properly and instead is being converted into a string.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setup.py`
Content:
```
1 from setuptools import setup
2 
3 
4 # Requirements used for submodules
5 plot = ['plotly>=4.0']
6 hyperopt = [
7     'scipy',
8     'scikit-learn',
9     'scikit-optimize>=0.7.0',
10     'filelock',
11     'joblib',
12     'progressbar2',
13 ]
14 
15 develop = [
16     'coveralls',
17     'flake8',
18     'flake8-tidy-imports',
19     'mypy',
20     'pytest',
21     'pytest-asyncio',
22     'pytest-cov',
23     'pytest-mock',
24     'pytest-random-order',
25 ]
26 
27 jupyter = [
28     'jupyter',
29     'nbstripout',
30     'ipykernel',
31     'nbconvert',
32 ]
33 
34 all_extra = plot + develop + jupyter + hyperopt
35 
36 setup(
37     tests_require=[
38         'pytest',
39         'pytest-asyncio',
40         'pytest-cov',
41         'pytest-mock',
42     ],
43     install_requires=[
44         # from requirements.txt
45         'ccxt>=1.79.69',
46         'SQLAlchemy',
47         'python-telegram-bot>=13.4',
48         'arrow>=0.17.0',
49         'cachetools',
50         'requests',
51         'urllib3',
52         'jsonschema',
53         'TA-Lib',
54         'pandas-ta',
55         'technical',
56         'tabulate',
57         'pycoingecko',
58         'py_find_1st',
59         'python-rapidjson',
60         'sdnotify',
61         'colorama',
62         'jinja2',
63         'questionary',
64         'prompt-toolkit',
65         'numpy',
66         'pandas',
67         'tables',
68         'blosc',
69         'fastapi',
70         'uvicorn',
71         'psutil',
72         'pyjwt',
73         'aiofiles',
74         'schedule'
75     ],
76     extras_require={
77         'dev': all_extra,
78         'plot': plot,
79         'jupyter': jupyter,
80         'hyperopt': hyperopt,
81         'all': all_extra,
82     },
83 )
84
```

Path: `freqtrade/rpc/api_server/webserver.py`
Content:
```
1 import logging
2 from ipaddress import IPv4Address
3 from typing import Any, Dict
4 
5 import rapidjson
6 import uvicorn
7 from fastapi import Depends, FastAPI
8 from fastapi.middleware.cors import CORSMiddleware
9 from starlette.responses import JSONResponse
10 
11 from freqtrade.exceptions import OperationalException
12 from freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer
13 from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler
14 
15 
16 logger = logging.getLogger(__name__)
17 
18 
19 class FTJSONResponse(JSONResponse):
20     media_type = "application/json"
21 
22     def render(self, content: Any) -> bytes:
23         """
24         Use rapidjson for responses
25         Handles NaN and Inf / -Inf in a javascript way by default.
26         """
27         return rapidjson.dumps(content).encode("utf-8")
28 
29 
30 class ApiServer(RPCHandler):
31 
32     __instance = None
33     __initialized = False
34 
35     _rpc: RPC
36     # Backtesting type: Backtesting
37     _bt = None
38     _bt_data = None
39     _bt_timerange = None
40     _bt_last_config: Dict[str, Any] = {}
41     _has_rpc: bool = False
42     _bgtask_running: bool = False
43     _config: Dict[str, Any] = {}
44     # Exchange - only available in webserver mode.
45     _exchange = None
46 
47     def __new__(cls, *args, **kwargs):
48         """
49         This class is a singleton.
50         We'll only have one instance of it around.
51         """
52         if ApiServer.__instance is None:
53             ApiServer.__instance = object.__new__(cls)
54             ApiServer.__initialized = False
55         return ApiServer.__instance
56 
57     def __init__(self, config: Dict[str, Any], standalone: bool = False) -> None:
58         ApiServer._config = config
59         if self.__initialized and (standalone or self._standalone):
60             return
61         self._standalone: bool = standalone
62         self._server = None
63         ApiServer.__initialized = True
64 
65         api_config = self._config['api_server']
66 
67         self.app = FastAPI(title="Freqtrade API",
68                            docs_url='/docs' if api_config.get('enable_openapi', False) else None,
69                            redoc_url=None,
70                            default_response_class=FTJSONResponse,
71                            )
72         self.configure_app(self.app, self._config)
73 
74         self.start_api()
75 
76     def add_rpc_handler(self, rpc: RPC):
77         """
78         Attach rpc handler
79         """
80         if not self._has_rpc:
81             ApiServer._rpc = rpc
82             ApiServer._has_rpc = True
83         else:
84             # This should not happen assuming we didn't mess up.
85             raise OperationalException('RPC Handler already attached.')
86 
87     def cleanup(self) -> None:
88         """ Cleanup pending module resources """
89         ApiServer._has_rpc = False
90         del ApiServer._rpc
91         if self._server and not self._standalone:
92             logger.info("Stopping API Server")
93             self._server.cleanup()
94 
95     @classmethod
96     def shutdown(cls):
97         cls.__initialized = False
98         del cls.__instance
99         cls.__instance = None
100         cls._has_rpc = False
101         cls._rpc = None
102 
103     def send_msg(self, msg: Dict[str, str]) -> None:
104         pass
105 
106     def handle_rpc_exception(self, request, exc):
107         logger.exception(f"API Error calling: {exc}")
108         return JSONResponse(
109             status_code=502,
110             content={'error': f"Error querying {request.url.path}: {exc.message}"}
111         )
112 
113     def configure_app(self, app: FastAPI, config):
114         from freqtrade.rpc.api_server.api_auth import http_basic_or_jwt_token, router_login
115         from freqtrade.rpc.api_server.api_backtest import router as api_backtest
116         from freqtrade.rpc.api_server.api_v1 import router as api_v1
117         from freqtrade.rpc.api_server.api_v1 import router_public as api_v1_public
118         from freqtrade.rpc.api_server.web_ui import router_ui
119 
120         app.include_router(api_v1_public, prefix="/api/v1")
121 
122         app.include_router(api_v1, prefix="/api/v1",
123                            dependencies=[Depends(http_basic_or_jwt_token)],
124                            )
125         app.include_router(api_backtest, prefix="/api/v1",
126                            dependencies=[Depends(http_basic_or_jwt_token)],
127                            )
128         app.include_router(router_login, prefix="/api/v1", tags=["auth"])
129         # UI Router MUST be last!
130         app.include_router(router_ui, prefix='')
131 
132         app.add_middleware(
133             CORSMiddleware,
134             allow_origins=config['api_server'].get('CORS_origins', []),
135             allow_credentials=True,
136             allow_methods=["*"],
137             allow_headers=["*"],
138         )
139 
140         app.add_exception_handler(RPCException, self.handle_rpc_exception)
141 
142     def start_api(self):
143         """
144         Start API ... should be run in thread.
145         """
146         rest_ip = self._config['api_server']['listen_ip_address']
147         rest_port = self._config['api_server']['listen_port']
148 
149         logger.info(f'Starting HTTP Server at {rest_ip}:{rest_port}')
150         if not IPv4Address(rest_ip).is_loopback:
151             logger.warning("SECURITY WARNING - Local Rest Server listening to external connections")
152             logger.warning("SECURITY WARNING - This is insecure please set to your loopback,"
153                            "e.g 127.0.0.1 in config.json")
154 
155         if not self._config['api_server'].get('password'):
156             logger.warning("SECURITY WARNING - No password for local REST Server defined. "
157                            "Please make sure that this is intentional!")
158 
159         if (self._config['api_server'].get('jwt_secret_key', 'super-secret')
160                 in ('super-secret, somethingrandom')):
161             logger.warning("SECURITY WARNING - `jwt_secret_key` seems to be default."
162                            "Others may be able to log into your bot.")
163 
164         logger.info('Starting Local Rest Server.')
165         verbosity = self._config['api_server'].get('verbosity', 'error')
166 
167         uvconfig = uvicorn.Config(self.app,
168                                   port=rest_port,
169                                   host=rest_ip,
170                                   use_colors=False,
171                                   log_config=None,
172                                   access_log=True if verbosity != 'error' else False,
173                                   )
174         try:
175             self._server = UvicornServer(uvconfig)
176             if self._standalone:
177                 self._server.run()
178             else:
179                 self._server.run_in_thread()
180         except Exception:
181             logger.exception("Api server failed to start.")
182
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py
--- a/freqtrade/rpc/api_server/webserver.py
+++ b/freqtrade/rpc/api_server/webserver.py
@@ -2,7 +2,7 @@
 from ipaddress import IPv4Address
 from typing import Any, Dict
 
-import rapidjson
+import orjson
 import uvicorn
 from fastapi import Depends, FastAPI
 from fastapi.middleware.cors import CORSMiddleware
@@ -24,7 +24,7 @@
         Use rapidjson for responses
         Handles NaN and Inf / -Inf in a javascript way by default.
         """
-        return rapidjson.dumps(content).encode("utf-8")
+        return orjson.dumps(content, option=orjson.OPT_SERIALIZE_NUMPY)
 
 
 class ApiServer(RPCHandler):
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -57,6 +57,7 @@
         'pycoingecko',
         'py_find_1st',
         'python-rapidjson',
+        'orjson',
         'sdnotify',
         'colorama',
         'jinja2',

{"golden_diff": "diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py\n--- a/freqtrade/rpc/api_server/webserver.py\n+++ b/freqtrade/rpc/api_server/webserver.py\n@@ -2,7 +2,7 @@\n from ipaddress import IPv4Address\n from typing import Any, Dict\n \n-import rapidjson\n+import orjson\n import uvicorn\n from fastapi import Depends, FastAPI\n from fastapi.middleware.cors import CORSMiddleware\n@@ -24,7 +24,7 @@\n         Use rapidjson for responses\n         Handles NaN and Inf / -Inf in a javascript way by default.\n         \"\"\"\n-        return rapidjson.dumps(content).encode(\"utf-8\")\n+        return orjson.dumps(content, option=orjson.OPT_SERIALIZE_NUMPY)\n \n \n class ApiServer(RPCHandler):\ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -57,6 +57,7 @@\n         'pycoingecko',\n         'py_find_1st',\n         'python-rapidjson',\n+        'orjson',\n         'sdnotify',\n         'colorama',\n         'jinja2',\n", "issue": "NaN values on /status\n<!-- \r\nHave you searched for similar issues before posting it?\r\n\r\nIf you have discovered a bug in the bot, please [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). \r\nIf it hasn't been reported, please create a new issue.\r\n\r\nPlease do not use bug reports to request new features.\r\n-->\r\n\r\n## Describe your environment\r\n\r\n  * Operating system: Raspbian\r\n  * Python Version: 3.9.9 (`python -V`)\r\n  * CCXT version: 1.80.61 (`pip freeze | grep ccxt`)\r\n  * Freqtrade Version: docker-44000ae0 (`freqtrade -V` or `docker-compose run --rm freqtrade -V` for Freqtrade running in docker)\r\n  \r\nNote: All issues other than enhancement requests will be closed without further comment if the above template is deleted or not filled out.\r\n\r\n## Describe the problem:\r\n\r\n*Explain the problem you have encountered*\r\n\r\n### Steps to reproduce:\r\n\r\n  1. Open FreqUI\r\n  2. Go to Dashboard\r\n  \r\n### Observed Results:\r\n\r\nDue to the API sending \"NaN\" as values, the frontend can't parse the JSON properly and instead is being converted into a string.\r\n\n", "before_files": [{"content": "from setuptools import setup\n\n\n# Requirements used for submodules\nplot = ['plotly>=4.0']\nhyperopt = [\n    'scipy',\n    'scikit-learn',\n    'scikit-optimize>=0.7.0',\n    'filelock',\n    'joblib',\n    'progressbar2',\n]\n\ndevelop = [\n    'coveralls',\n    'flake8',\n    'flake8-tidy-imports',\n    'mypy',\n    'pytest',\n    'pytest-asyncio',\n    'pytest-cov',\n    'pytest-mock',\n    'pytest-random-order',\n]\n\njupyter = [\n    'jupyter',\n    'nbstripout',\n    'ipykernel',\n    'nbconvert',\n]\n\nall_extra = plot + develop + jupyter + hyperopt\n\nsetup(\n    tests_require=[\n        'pytest',\n        'pytest-asyncio',\n        'pytest-cov',\n        'pytest-mock',\n    ],\n    install_requires=[\n        # from requirements.txt\n        'ccxt>=1.79.69',\n        'SQLAlchemy',\n        'python-telegram-bot>=13.4',\n        'arrow>=0.17.0',\n        'cachetools',\n        'requests',\n        'urllib3',\n        'jsonschema',\n        'TA-Lib',\n        'pandas-ta',\n        'technical',\n        'tabulate',\n        'pycoingecko',\n        'py_find_1st',\n        'python-rapidjson',\n        'sdnotify',\n        'colorama',\n        'jinja2',\n        'questionary',\n        'prompt-toolkit',\n        'numpy',\n        'pandas',\n        'tables',\n        'blosc',\n        'fastapi',\n        'uvicorn',\n        'psutil',\n        'pyjwt',\n        'aiofiles',\n        'schedule'\n    ],\n    extras_require={\n        'dev': all_extra,\n        'plot': plot,\n        'jupyter': jupyter,\n        'hyperopt': hyperopt,\n        'all': all_extra,\n    },\n)\n", "path": "setup.py"}, {"content": "import logging\nfrom ipaddress import IPv4Address\nfrom typing import Any, Dict\n\nimport rapidjson\nimport uvicorn\nfrom fastapi import Depends, FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom starlette.responses import JSONResponse\n\nfrom freqtrade.exceptions import OperationalException\nfrom freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer\nfrom freqtrade.rpc.rpc import RPC, RPCException, RPCHandler\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass FTJSONResponse(JSONResponse):\n    media_type = \"application/json\"\n\n    def render(self, content: Any) -> bytes:\n        \"\"\"\n        Use rapidjson for responses\n        Handles NaN and Inf / -Inf in a javascript way by default.\n        \"\"\"\n        return rapidjson.dumps(content).encode(\"utf-8\")\n\n\nclass ApiServer(RPCHandler):\n\n    __instance = None\n    __initialized = False\n\n    _rpc: RPC\n    # Backtesting type: Backtesting\n    _bt = None\n    _bt_data = None\n    _bt_timerange = None\n    _bt_last_config: Dict[str, Any] = {}\n    _has_rpc: bool = False\n    _bgtask_running: bool = False\n    _config: Dict[str, Any] = {}\n    # Exchange - only available in webserver mode.\n    _exchange = None\n\n    def __new__(cls, *args, **kwargs):\n        \"\"\"\n        This class is a singleton.\n        We'll only have one instance of it around.\n        \"\"\"\n        if ApiServer.__instance is None:\n            ApiServer.__instance = object.__new__(cls)\n            ApiServer.__initialized = False\n        return ApiServer.__instance\n\n    def __init__(self, config: Dict[str, Any], standalone: bool = False) -> None:\n        ApiServer._config = config\n        if self.__initialized and (standalone or self._standalone):\n            return\n        self._standalone: bool = standalone\n        self._server = None\n        ApiServer.__initialized = True\n\n        api_config = self._config['api_server']\n\n        self.app = FastAPI(title=\"Freqtrade API\",\n                           docs_url='/docs' if api_config.get('enable_openapi', False) else None,\n                           redoc_url=None,\n                           default_response_class=FTJSONResponse,\n                           )\n        self.configure_app(self.app, self._config)\n\n        self.start_api()\n\n    def add_rpc_handler(self, rpc: RPC):\n        \"\"\"\n        Attach rpc handler\n        \"\"\"\n        if not self._has_rpc:\n            ApiServer._rpc = rpc\n            ApiServer._has_rpc = True\n        else:\n            # This should not happen assuming we didn't mess up.\n            raise OperationalException('RPC Handler already attached.')\n\n    def cleanup(self) -> None:\n        \"\"\" Cleanup pending module resources \"\"\"\n        ApiServer._has_rpc = False\n        del ApiServer._rpc\n        if self._server and not self._standalone:\n            logger.info(\"Stopping API Server\")\n            self._server.cleanup()\n\n    @classmethod\n    def shutdown(cls):\n        cls.__initialized = False\n        del cls.__instance\n        cls.__instance = None\n        cls._has_rpc = False\n        cls._rpc = None\n\n    def send_msg(self, msg: Dict[str, str]) -> None:\n        pass\n\n    def handle_rpc_exception(self, request, exc):\n        logger.exception(f\"API Error calling: {exc}\")\n        return JSONResponse(\n            status_code=502,\n            content={'error': f\"Error querying {request.url.path}: {exc.message}\"}\n        )\n\n    def configure_app(self, app: FastAPI, config):\n        from freqtrade.rpc.api_server.api_auth import http_basic_or_jwt_token, router_login\n        from freqtrade.rpc.api_server.api_backtest import router as api_backtest\n        from freqtrade.rpc.api_server.api_v1 import router as api_v1\n        from freqtrade.rpc.api_server.api_v1 import router_public as api_v1_public\n        from freqtrade.rpc.api_server.web_ui import router_ui\n\n        app.include_router(api_v1_public, prefix=\"/api/v1\")\n\n        app.include_router(api_v1, prefix=\"/api/v1\",\n                           dependencies=[Depends(http_basic_or_jwt_token)],\n                           )\n        app.include_router(api_backtest, prefix=\"/api/v1\",\n                           dependencies=[Depends(http_basic_or_jwt_token)],\n                           )\n        app.include_router(router_login, prefix=\"/api/v1\", tags=[\"auth\"])\n        # UI Router MUST be last!\n        app.include_router(router_ui, prefix='')\n\n        app.add_middleware(\n            CORSMiddleware,\n            allow_origins=config['api_server'].get('CORS_origins', []),\n            allow_credentials=True,\n            allow_methods=[\"*\"],\n            allow_headers=[\"*\"],\n        )\n\n        app.add_exception_handler(RPCException, self.handle_rpc_exception)\n\n    def start_api(self):\n        \"\"\"\n        Start API ... should be run in thread.\n        \"\"\"\n        rest_ip = self._config['api_server']['listen_ip_address']\n        rest_port = self._config['api_server']['listen_port']\n\n        logger.info(f'Starting HTTP Server at {rest_ip}:{rest_port}')\n        if not IPv4Address(rest_ip).is_loopback:\n            logger.warning(\"SECURITY WARNING - Local Rest Server listening to external connections\")\n            logger.warning(\"SECURITY WARNING - This is insecure please set to your loopback,\"\n                           \"e.g 127.0.0.1 in config.json\")\n\n        if not self._config['api_server'].get('password'):\n            logger.warning(\"SECURITY WARNING - No password for local REST Server defined. \"\n                           \"Please make sure that this is intentional!\")\n\n        if (self._config['api_server'].get('jwt_secret_key', 'super-secret')\n                in ('super-secret, somethingrandom')):\n            logger.warning(\"SECURITY WARNING - `jwt_secret_key` seems to be default.\"\n                           \"Others may be able to log into your bot.\")\n\n        logger.info('Starting Local Rest Server.')\n        verbosity = self._config['api_server'].get('verbosity', 'error')\n\n        uvconfig = uvicorn.Config(self.app,\n                                  port=rest_port,\n                                  host=rest_ip,\n                                  use_colors=False,\n                                  log_config=None,\n                                  access_log=True if verbosity != 'error' else False,\n                                  )\n        try:\n            self._server = UvicornServer(uvconfig)\n            if self._standalone:\n                self._server.run()\n            else:\n                self._server.run_in_thread()\n        except Exception:\n            logger.exception(\"Api server failed to start.\")\n", "path": "freqtrade/rpc/api_server/webserver.py"}], "after_files": [{"content": "from setuptools import setup\n\n\n# Requirements used for submodules\nplot = ['plotly>=4.0']\nhyperopt = [\n    'scipy',\n    'scikit-learn',\n    'scikit-optimize>=0.7.0',\n    'filelock',\n    'joblib',\n    'progressbar2',\n]\n\ndevelop = [\n    'coveralls',\n    'flake8',\n    'flake8-tidy-imports',\n    'mypy',\n    'pytest',\n    'pytest-asyncio',\n    'pytest-cov',\n    'pytest-mock',\n    'pytest-random-order',\n]\n\njupyter = [\n    'jupyter',\n    'nbstripout',\n    'ipykernel',\n    'nbconvert',\n]\n\nall_extra = plot + develop + jupyter + hyperopt\n\nsetup(\n    tests_require=[\n        'pytest',\n        'pytest-asyncio',\n        'pytest-cov',\n        'pytest-mock',\n    ],\n    install_requires=[\n        # from requirements.txt\n        'ccxt>=1.79.69',\n        'SQLAlchemy',\n        'python-telegram-bot>=13.4',\n        'arrow>=0.17.0',\n        'cachetools',\n        'requests',\n        'urllib3',\n        'jsonschema',\n        'TA-Lib',\n        'pandas-ta',\n        'technical',\n        'tabulate',\n        'pycoingecko',\n        'py_find_1st',\n        'python-rapidjson',\n        'orjson',\n        'sdnotify',\n        'colorama',\n        'jinja2',\n        'questionary',\n        'prompt-toolkit',\n        'numpy',\n        'pandas',\n        'tables',\n        'blosc',\n        'fastapi',\n        'uvicorn',\n        'psutil',\n        'pyjwt',\n        'aiofiles',\n        'schedule'\n    ],\n    extras_require={\n        'dev': all_extra,\n        'plot': plot,\n        'jupyter': jupyter,\n        'hyperopt': hyperopt,\n        'all': all_extra,\n    },\n)\n", "path": "setup.py"}, {"content": "import logging\nfrom ipaddress import IPv4Address\nfrom typing import Any, Dict\n\nimport orjson\nimport uvicorn\nfrom fastapi import Depends, FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom starlette.responses import JSONResponse\n\nfrom freqtrade.exceptions import OperationalException\nfrom freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer\nfrom freqtrade.rpc.rpc import RPC, RPCException, RPCHandler\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass FTJSONResponse(JSONResponse):\n    media_type = \"application/json\"\n\n    def render(self, content: Any) -> bytes:\n        \"\"\"\n        Use rapidjson for responses\n        Handles NaN and Inf / -Inf in a javascript way by default.\n        \"\"\"\n        return orjson.dumps(content, option=orjson.OPT_SERIALIZE_NUMPY)\n\n\nclass ApiServer(RPCHandler):\n\n    __instance = None\n    __initialized = False\n\n    _rpc: RPC\n    # Backtesting type: Backtesting\n    _bt = None\n    _bt_data = None\n    _bt_timerange = None\n    _bt_last_config: Dict[str, Any] = {}\n    _has_rpc: bool = False\n    _bgtask_running: bool = False\n    _config: Dict[str, Any] = {}\n    # Exchange - only available in webserver mode.\n    _exchange = None\n\n    def __new__(cls, *args, **kwargs):\n        \"\"\"\n        This class is a singleton.\n        We'll only have one instance of it around.\n        \"\"\"\n        if ApiServer.__instance is None:\n            ApiServer.__instance = object.__new__(cls)\n            ApiServer.__initialized = False\n        return ApiServer.__instance\n\n    def __init__(self, config: Dict[str, Any], standalone: bool = False) -> None:\n        ApiServer._config = config\n        if self.__initialized and (standalone or self._standalone):\n            return\n        self._standalone: bool = standalone\n        self._server = None\n        ApiServer.__initialized = True\n\n        api_config = self._config['api_server']\n\n        self.app = FastAPI(title=\"Freqtrade API\",\n                           docs_url='/docs' if api_config.get('enable_openapi', False) else None,\n                           redoc_url=None,\n                           default_response_class=FTJSONResponse,\n                           )\n        self.configure_app(self.app, self._config)\n\n        self.start_api()\n\n    def add_rpc_handler(self, rpc: RPC):\n        \"\"\"\n        Attach rpc handler\n        \"\"\"\n        if not self._has_rpc:\n            ApiServer._rpc = rpc\n            ApiServer._has_rpc = True\n        else:\n            # This should not happen assuming we didn't mess up.\n            raise OperationalException('RPC Handler already attached.')\n\n    def cleanup(self) -> None:\n        \"\"\" Cleanup pending module resources \"\"\"\n        ApiServer._has_rpc = False\n        del ApiServer._rpc\n        if self._server and not self._standalone:\n            logger.info(\"Stopping API Server\")\n            self._server.cleanup()\n\n    @classmethod\n    def shutdown(cls):\n        cls.__initialized = False\n        del cls.__instance\n        cls.__instance = None\n        cls._has_rpc = False\n        cls._rpc = None\n\n    def send_msg(self, msg: Dict[str, str]) -> None:\n        pass\n\n    def handle_rpc_exception(self, request, exc):\n        logger.exception(f\"API Error calling: {exc}\")\n        return JSONResponse(\n            status_code=502,\n            content={'error': f\"Error querying {request.url.path}: {exc.message}\"}\n        )\n\n    def configure_app(self, app: FastAPI, config):\n        from freqtrade.rpc.api_server.api_auth import http_basic_or_jwt_token, router_login\n        from freqtrade.rpc.api_server.api_backtest import router as api_backtest\n        from freqtrade.rpc.api_server.api_v1 import router as api_v1\n        from freqtrade.rpc.api_server.api_v1 import router_public as api_v1_public\n        from freqtrade.rpc.api_server.web_ui import router_ui\n\n        app.include_router(api_v1_public, prefix=\"/api/v1\")\n\n        app.include_router(api_v1, prefix=\"/api/v1\",\n                           dependencies=[Depends(http_basic_or_jwt_token)],\n                           )\n        app.include_router(api_backtest, prefix=\"/api/v1\",\n                           dependencies=[Depends(http_basic_or_jwt_token)],\n                           )\n        app.include_router(router_login, prefix=\"/api/v1\", tags=[\"auth\"])\n        # UI Router MUST be last!\n        app.include_router(router_ui, prefix='')\n\n        app.add_middleware(\n            CORSMiddleware,\n            allow_origins=config['api_server'].get('CORS_origins', []),\n            allow_credentials=True,\n            allow_methods=[\"*\"],\n            allow_headers=[\"*\"],\n        )\n\n        app.add_exception_handler(RPCException, self.handle_rpc_exception)\n\n    def start_api(self):\n        \"\"\"\n        Start API ... should be run in thread.\n        \"\"\"\n        rest_ip = self._config['api_server']['listen_ip_address']\n        rest_port = self._config['api_server']['listen_port']\n\n        logger.info(f'Starting HTTP Server at {rest_ip}:{rest_port}')\n        if not IPv4Address(rest_ip).is_loopback:\n            logger.warning(\"SECURITY WARNING - Local Rest Server listening to external connections\")\n            logger.warning(\"SECURITY WARNING - This is insecure please set to your loopback,\"\n                           \"e.g 127.0.0.1 in config.json\")\n\n        if not self._config['api_server'].get('password'):\n            logger.warning(\"SECURITY WARNING - No password for local REST Server defined. \"\n                           \"Please make sure that this is intentional!\")\n\n        if (self._config['api_server'].get('jwt_secret_key', 'super-secret')\n                in ('super-secret, somethingrandom')):\n            logger.warning(\"SECURITY WARNING - `jwt_secret_key` seems to be default.\"\n                           \"Others may be able to log into your bot.\")\n\n        logger.info('Starting Local Rest Server.')\n        verbosity = self._config['api_server'].get('verbosity', 'error')\n\n        uvconfig = uvicorn.Config(self.app,\n                                  port=rest_port,\n                                  host=rest_ip,\n                                  use_colors=False,\n                                  log_config=None,\n                                  access_log=True if verbosity != 'error' else False,\n                                  )\n        try:\n            self._server = UvicornServer(uvconfig)\n            if self._standalone:\n                self._server.run()\n            else:\n                self._server.run_in_thread()\n        except Exception:\n            logger.exception(\"Api server failed to start.\")\n", "path": "freqtrade/rpc/api_server/webserver.py"}]}