renewed development
This commit is contained in:
parent
e97f76222c
commit
8b115cee75
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -15,9 +15,6 @@
|
|||||||
],
|
],
|
||||||
"python.envFile": "${workspaceFolder}/.env",
|
"python.envFile": "${workspaceFolder}/.env",
|
||||||
"python.testing.debugPort": 3000,
|
"python.testing.debugPort": 3000,
|
||||||
"python.linting.enabled": true,
|
|
||||||
"python.linting.pylintEnabled": false,
|
|
||||||
"python.linting.mypyEnabled": true,
|
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.py": "python"
|
"*.py": "python"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Dict, Any, List, Optional
|
import asyncio
|
||||||
|
from typing import Callable, Dict, Any, List, Optional
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@ -63,7 +64,6 @@ class RESTSender(NamedObject):
|
|||||||
f"Failed to send status={excpt.response.status_code} {excpt.response.text}" # type: ignore
|
f"Failed to send status={excpt.response.status_code} {excpt.response.text}" # type: ignore
|
||||||
) from excpt
|
) from excpt
|
||||||
|
|
||||||
|
|
||||||
class MdSummary(HistMdBar):
|
class MdSummary(HistMdBar):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -105,6 +105,7 @@ class MdSummary(HistMdBar):
|
|||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
MdSummaryCallbackT = Callable[[List[MdSummary]], None]
|
||||||
|
|
||||||
class MdSummaryCollector(NamedObject):
|
class MdSummaryCollector(NamedObject):
|
||||||
sender_: RESTSender
|
sender_: RESTSender
|
||||||
@ -114,6 +115,7 @@ class MdSummaryCollector(NamedObject):
|
|||||||
history_depth_sec_: int
|
history_depth_sec_: int
|
||||||
|
|
||||||
history_: List[MdSummary]
|
history_: List[MdSummary]
|
||||||
|
callbacks_: List[MdSummaryCallbackT]
|
||||||
timer_: Optional[Timer]
|
timer_: Optional[Timer]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -130,9 +132,13 @@ class MdSummaryCollector(NamedObject):
|
|||||||
self.interval_sec_ = interval_sec
|
self.interval_sec_ = interval_sec
|
||||||
self.history_depth_sec_ = history_depth_sec
|
self.history_depth_sec_ = history_depth_sec
|
||||||
|
|
||||||
self.history_depth_sec_ = []
|
self.history_ = []
|
||||||
|
self.callbacks_ = []
|
||||||
self.timer_ = None
|
self.timer_ = None
|
||||||
|
|
||||||
|
def add_callback(self, cb: MdSummaryCallbackT) -> None:
|
||||||
|
self.callbacks_.append(cb)
|
||||||
|
|
||||||
def rqst_data(self) -> Dict[str, Any]:
|
def rqst_data(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"exch_acct": self.exch_acct_,
|
"exch_acct": self.exch_acct_,
|
||||||
@ -145,22 +151,32 @@ class MdSummaryCollector(NamedObject):
|
|||||||
response: requests.Response = self.sender_.send_post(
|
response: requests.Response = self.sender_.send_post(
|
||||||
endpoint="md_summary", post_body=self.rqst_data()
|
endpoint="md_summary", post_body=self.rqst_data()
|
||||||
)
|
)
|
||||||
|
if response.status_code not in (200, 201):
|
||||||
|
Log.error(f"{self.fname()}: Received error: {response.status_code} - {response.text}")
|
||||||
|
return []
|
||||||
return MdSummary.from_REST_response(response=response)
|
return MdSummary.from_REST_response(response=response)
|
||||||
|
|
||||||
def get_last(self) -> Optional[MdSummary]:
|
def get_last(self) -> Optional[MdSummary]:
|
||||||
rqst_data = self.rqst_data()
|
rqst_data = self.rqst_data()
|
||||||
rqst_data["history_depth_sec"] = self.interval_sec_
|
rqst_data["history_depth_sec"] = self.interval_sec_ * 2
|
||||||
response: requests.Response = self.sender_.send_post(
|
response: requests.Response = self.sender_.send_post(
|
||||||
endpoint="md_summary", post_body=rqst_data
|
endpoint="md_summary", post_body=rqst_data
|
||||||
)
|
)
|
||||||
|
if response.status_code not in (200, 201):
|
||||||
|
Log.error(f"{self.fname()}: Received error: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
res = MdSummary.from_REST_response(response=response)
|
res = MdSummary.from_REST_response(response=response)
|
||||||
return None if len(res) == 0 else res[-1]
|
return None if len(res) == 0 else res[-1]
|
||||||
|
|
||||||
|
def is_empty(self) -> bool:
|
||||||
|
return len(self.history_) == 0
|
||||||
|
|
||||||
async def start(self) -> None:
|
async def start(self) -> None:
|
||||||
if self.timer_:
|
if self.timer_:
|
||||||
Log.error(f"{self.fname()}: Timer is already started")
|
Log.error(f"{self.fname()}: Timer is already started")
|
||||||
return
|
return
|
||||||
self.history_ = self.get_history()
|
self.history_ = self.get_history()
|
||||||
|
self.run_callbacks()
|
||||||
self.timer_ = Timer(
|
self.timer_ = Timer(
|
||||||
start_in_sec=self.interval_sec_,
|
start_in_sec=self.interval_sec_,
|
||||||
is_periodic=True,
|
is_periodic=True,
|
||||||
@ -169,15 +185,19 @@ class MdSummaryCollector(NamedObject):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def _load_new(self) -> None:
|
async def _load_new(self) -> None:
|
||||||
|
|
||||||
last: Optional[MdSummary] = self.get_last()
|
last: Optional[MdSummary] = self.get_last()
|
||||||
if not last:
|
if not last:
|
||||||
# URGENT logging
|
Log.warning(f"{self.fname()}: did not get last update")
|
||||||
return
|
return
|
||||||
if last.ts_ns_ <= self.history_[-1].ts_ns_:
|
if not self.is_empty() and last.ts_ns_ <= self.history_[-1].ts_ns_:
|
||||||
# URGENT logging
|
Log.info(f"{self.fname()}: Received {last}. Already Have: {self.history_[-1]}")
|
||||||
return
|
return
|
||||||
self.history_.append(last)
|
self.history_.append(last)
|
||||||
# URGENT implement notification
|
self.run_callbacks()
|
||||||
|
|
||||||
|
def run_callbacks(self) -> None:
|
||||||
|
[cb(self.history_) for cb in self.callbacks_]
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
if self.timer_:
|
if self.timer_:
|
||||||
@ -196,7 +216,8 @@ class CvttRESTClient(NamedObject):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = Config(json_src={"cvtt_base_url": "http://cvtt-tester-01.cvtt.vpn:23456"})
|
# config = Config(json_src={"cvtt_base_url": "http://cvtt-tester-01.cvtt.vpn:23456"})
|
||||||
|
config = Config(json_src={"cvtt_base_url": "http://dev-server-02.cvtt.vpn:23456"})
|
||||||
|
|
||||||
cvtt_client = CvttRESTClient(config)
|
cvtt_client = CvttRESTClient(config)
|
||||||
|
|
||||||
@ -208,6 +229,16 @@ if __name__ == "__main__":
|
|||||||
history_depth_sec=24 * 3600,
|
history_depth_sec=24 * 3600,
|
||||||
)
|
)
|
||||||
|
|
||||||
hist = mdsc.get_history()
|
def _calback(history: List[MdSummary]) -> None:
|
||||||
last = mdsc.get_last()
|
Log.info(f"MdSummary Hist Length is {len(history)}. Last summary: {history[-1] if len(history) > 0 else '[]'}")
|
||||||
|
|
||||||
|
mdsc.add_callback(_calback)
|
||||||
|
|
||||||
|
async def __run() -> None:
|
||||||
|
Log.info("Starting...")
|
||||||
|
await mdsc.start()
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
asyncio.run(__run())
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -12,11 +12,11 @@ from cvttpy_tools.settings.cvtt_types import JsonDictT
|
|||||||
# ---
|
# ---
|
||||||
from cvttpy_trading.trading.instrument import ExchangeInstrument
|
from cvttpy_trading.trading.instrument import ExchangeInstrument
|
||||||
# ---
|
# ---
|
||||||
from pt_strategy.live.ti_sender import TradingInstructionsSender
|
from pairs_trading.lib.pt_strategy.live.ti_sender import TradingInstructionsSender
|
||||||
from pt_strategy.model_data_policy import ModelDataPolicy
|
from pairs_trading.lib.pt_strategy.model_data_policy import ModelDataPolicy
|
||||||
from pt_strategy.pt_market_data import RealTimeMarketData
|
from pairs_trading.lib.pt_strategy.pt_market_data import RealTimeMarketData
|
||||||
from pt_strategy.pt_model import Prediction
|
from pairs_trading.lib.pt_strategy.pt_model import Prediction
|
||||||
from pt_strategy.trading_pair import PairState, TradingPair
|
from pairs_trading.lib.pt_strategy.trading_pair import PairState, TradingPair
|
||||||
|
|
||||||
"""
|
"""
|
||||||
--config=pair.cfg
|
--config=pair.cfg
|
||||||
@ -104,9 +104,9 @@ class PtLiveStrategy(NamedObject):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def _send_trading_instructions(
|
async def _send_trading_instructions(
|
||||||
self, trading_instructions: pd.DataFrame
|
self, trading_instructions: List[TradingInstruction]
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass # URGENT implement _send_trading_instructions
|
||||||
|
|
||||||
def _create_trading_instructions(
|
def _create_trading_instructions(
|
||||||
self, prediction: Prediction, last_row: pd.Series
|
self, prediction: Prediction, last_row: pd.Series
|
||||||
@ -186,6 +186,11 @@ class PtLiveStrategy(NamedObject):
|
|||||||
}
|
}
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
def _create_close_trade_instructions(
|
||||||
|
self, pair: TradingPair, row: pd.Series #, prediction: Prediction
|
||||||
|
) -> List[TradingInstruction]:
|
||||||
|
return [] # URGENT implement _create_close_trade_instructions
|
||||||
|
|
||||||
def _handle_outstanding_positions(self) -> Optional[pd.DataFrame]:
|
def _handle_outstanding_positions(self) -> Optional[pd.DataFrame]:
|
||||||
trades = None
|
trades = None
|
||||||
pair = self.trading_pair_
|
pair = self.trading_pair_
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
|
```python
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from cvtt_client.mkt_data import (CvttPricerWebSockClient,
|
# from cvtt_client.mkt_data import (CvttPricerWebSockClient,
|
||||||
CvttPricesSubscription, MessageTypeT,
|
# CvttPricesSubscription, MessageTypeT,
|
||||||
SubscriptionIdT)
|
# SubscriptionIdT)
|
||||||
from cvttpy_tools.app import App
|
from cvttpy_tools.app import App
|
||||||
from cvttpy_tools.base import NamedObject
|
from cvttpy_tools.base import NamedObject
|
||||||
from cvttpy_tools.config import Config
|
from cvttpy_tools.config import Config
|
||||||
from cvttpy_tools.logger import Log
|
from cvttpy_tools.logger import Log
|
||||||
from cvttpy_tools.settings.cvtt_types import JsonDictT
|
from cvttpy_tools.settings.cvtt_types import JsonDictT
|
||||||
from pt_strategy.live.live_strategy import PtLiveStrategy
|
from pairs_trading.lib.pt_strategy.live.live_strategy import PtLiveStrategy
|
||||||
from pt_strategy.trading_pair import TradingPair
|
from pairs_trading.lib.pt_strategy.trading_pair import TradingPair
|
||||||
|
|
||||||
"""
|
"""
|
||||||
--config=pair.cfg
|
--config=pair.cfg
|
||||||
@ -83,3 +84,4 @@ class PtMktDataClient(NamedObject):
|
|||||||
await self._subscribe()
|
await self._subscribe()
|
||||||
|
|
||||||
await self.pricer_client_.run()
|
await self.pricer_client_.run()
|
||||||
|
```
|
||||||
@ -1,66 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools>=45", "wheel"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "pairs-trading"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Pairs Trading Backtesting Framework"
|
|
||||||
requires-python = ">=3.8"
|
|
||||||
|
|
||||||
[tool.black]
|
|
||||||
line-length = 88
|
|
||||||
target-version = ['py38']
|
|
||||||
include = '\.pyi?$'
|
|
||||||
extend-exclude = '''
|
|
||||||
/(
|
|
||||||
# directories
|
|
||||||
\.eggs
|
|
||||||
| \.git
|
|
||||||
| \.hg
|
|
||||||
| \.mypy_cache
|
|
||||||
| \.tox
|
|
||||||
| \.venv
|
|
||||||
| build
|
|
||||||
| dist
|
|
||||||
)/
|
|
||||||
'''
|
|
||||||
|
|
||||||
[tool.flake8]
|
|
||||||
max-line-length = 88
|
|
||||||
extend-ignore = ["E203", "W503"]
|
|
||||||
exclude = [
|
|
||||||
".git",
|
|
||||||
"__pycache__",
|
|
||||||
"build",
|
|
||||||
"dist",
|
|
||||||
".venv",
|
|
||||||
".mypy_cache",
|
|
||||||
".tox"
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
python_version = "3.8"
|
|
||||||
warn_return_any = true
|
|
||||||
warn_unused_configs = true
|
|
||||||
disallow_untyped_defs = true
|
|
||||||
disallow_incomplete_defs = true
|
|
||||||
check_untyped_defs = true
|
|
||||||
disallow_untyped_decorators = true
|
|
||||||
no_implicit_optional = true
|
|
||||||
warn_redundant_casts = true
|
|
||||||
warn_unused_ignores = true
|
|
||||||
warn_no_return = true
|
|
||||||
warn_unreachable = true
|
|
||||||
strict_equality = true
|
|
||||||
|
|
||||||
[[tool.mypy.overrides]]
|
|
||||||
module = [
|
|
||||||
"numpy.*",
|
|
||||||
"pandas.*",
|
|
||||||
"matplotlib.*",
|
|
||||||
"seaborn.*",
|
|
||||||
"scipy.*",
|
|
||||||
"sklearn.*"
|
|
||||||
]
|
|
||||||
ignore_missing_imports = true
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"include": [
|
|
||||||
"lib"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules",
|
|
||||||
"**/__pycache__",
|
|
||||||
"**/.*",
|
|
||||||
"results",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"ignore": [],
|
|
||||||
"defineConstant": {},
|
|
||||||
"typeCheckingMode": "basic",
|
|
||||||
"useLibraryCodeForTypes": true,
|
|
||||||
"autoImportCompletions": true,
|
|
||||||
"autoSearchPaths": true,
|
|
||||||
"extraPaths": [
|
|
||||||
"lib",
|
|
||||||
".."
|
|
||||||
],
|
|
||||||
"stubPath": "./typings",
|
|
||||||
"venvPath": ".",
|
|
||||||
"venv": "python3.12-venv"
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user