wiz-trader 0.34.0__py3-none-any.whl → 0.35.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wiz_trader/__init__.py CHANGED
@@ -3,6 +3,6 @@
3
3
  from .quotes import QuotesClient
4
4
  from .apis import WizzerClient
5
5
 
6
- __version__ = "0.34.0"
6
+ __version__ = "0.35.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -160,6 +160,13 @@ class WizzerClient:
160
160
  WEIGHTAGE_SCHEME_FLOAT_ADJUSTED_MARKET_CAP_WEIGHTED = "float_adjusted_market_cap_weighted"
161
161
  WEIGHTAGE_SCHEME_FUNDAMENTAL_WEIGHTED = "fundamental_weighted"
162
162
  WEIGHTAGE_SCHEME_CUSTOM_WEIGHTED = "custom_weighted"
163
+
164
+ # KV data type constants
165
+ KV_TYPE_STRING = "string"
166
+ KV_TYPE_BOOLEAN = "boolean"
167
+ KV_TYPE_NUMBER = "number"
168
+ KV_TYPE_ARRAY = "array"
169
+ KV_TYPE_OBJECT = "object"
163
170
 
164
171
  # URIs to various API endpoints
165
172
  _routes = {
@@ -209,7 +216,17 @@ class WizzerClient:
209
216
 
210
217
  # Screener API endpoints
211
218
  "screener.run": "/datahub/screener",
212
- "screener.fields": "/datahub/screener/metadata"
219
+ "screener.fields": "/datahub/screener/metadata",
220
+
221
+ # KV store endpoints
222
+ "kv.create": "/kv/{strategy_id}/{key}",
223
+ "kv.get": "/kv/{strategy_id}/{key}",
224
+ "kv.update": "/kv/{strategy_id}/{key}",
225
+ "kv.patch": "/kv/{strategy_id}/{key}",
226
+ "kv.delete": "/kv/{strategy_id}/{key}",
227
+ "kv.list": "/kv/{strategy_id}",
228
+ "kv.keys": "/kv/{strategy_id}/keys",
229
+ "kv.delete_all": "/kv/{strategy_id}/all"
213
230
  }
214
231
 
215
232
  def __init__(
@@ -1794,3 +1811,426 @@ class WizzerClient:
1794
1811
  if hasattr(e.response, 'text'):
1795
1812
  logger.error("Response content: %s", e.response.text)
1796
1813
  raise
1814
+
1815
+ # ===== KV STORE METHODS =====
1816
+
1817
+ def create_kv(self, key: str, value: Any, ttl: Optional[int] = None) -> Dict[str, Any]:
1818
+ """
1819
+ Create a new key-value pair.
1820
+
1821
+ Args:
1822
+ key (str): The key for the KV pair.
1823
+ value (Any): The value to store (any JSON-serializable type).
1824
+ ttl (Optional[int]): Time to live in seconds. If provided, the key will expire after this duration.
1825
+
1826
+ Returns:
1827
+ Dict[str, Any]: Response containing key, value, type, ttl, createdAt, updatedAt.
1828
+
1829
+ Example Response:
1830
+ {
1831
+ "key": "state",
1832
+ "value": {"positions": 30},
1833
+ "type": "object",
1834
+ "ttl": 100,
1835
+ "createdAt": "2023-10-01T10:00:00Z",
1836
+ "updatedAt": "2023-10-01T10:00:00Z"
1837
+ }
1838
+
1839
+ Raises:
1840
+ ValueError: If key is empty or invalid.
1841
+ requests.RequestException: If key already exists (409 Conflict) or API request fails.
1842
+
1843
+ Example:
1844
+ client.create_kv(key="portfolio_state", value={"positions": 30}, ttl=3600)
1845
+ """
1846
+ if not key or not key.strip():
1847
+ raise ValueError("Key cannot be empty or whitespace")
1848
+
1849
+ # Get strategy information
1850
+ strategy_info = self._get_strategy()
1851
+ endpoint = self._routes["kv.create"].format(strategy_id=strategy_info["id"], key=key)
1852
+
1853
+ # Build request payload
1854
+ data = {"value": value}
1855
+ if ttl is not None:
1856
+ data["ttl"] = ttl
1857
+
1858
+ logger.debug("Creating KV pair: key=%s, type=%s, ttl=%s", key, type(value).__name__, ttl)
1859
+ return self._make_request("POST", endpoint, json=data)
1860
+
1861
+ def get_kv(self, key: str) -> Dict[str, Any]:
1862
+ """
1863
+ Retrieve a key-value pair.
1864
+
1865
+ Args:
1866
+ key (str): The key to retrieve.
1867
+
1868
+ Returns:
1869
+ Dict[str, Any]: Response containing value, type, and optional ttl.
1870
+
1871
+ Example Response:
1872
+ {
1873
+ "value": {"positions": 30},
1874
+ "type": "object",
1875
+ "ttl": 85
1876
+ }
1877
+
1878
+ Raises:
1879
+ ValueError: If key is empty or invalid.
1880
+ requests.RequestException: If key not found (404) or API request fails.
1881
+
1882
+ Example:
1883
+ data = client.get_kv("portfolio_state")
1884
+ positions = data["value"]["positions"]
1885
+ """
1886
+ if not key or not key.strip():
1887
+ raise ValueError("Key cannot be empty or whitespace")
1888
+
1889
+ # Get strategy information
1890
+ strategy_info = self._get_strategy()
1891
+ endpoint = self._routes["kv.get"].format(strategy_id=strategy_info["id"], key=key)
1892
+
1893
+ logger.debug("Retrieving KV pair: key=%s", key)
1894
+ return self._make_request("GET", endpoint)
1895
+
1896
+ def update_kv(self, key: str, value: Any, ttl: Optional[int] = None) -> Dict[str, Any]:
1897
+ """
1898
+ Update (replace) an existing key-value pair completely.
1899
+
1900
+ Args:
1901
+ key (str): The key to update.
1902
+ value (Any): The new value to store (any JSON-serializable type).
1903
+ ttl (Optional[int]): New time to live in seconds.
1904
+
1905
+ Returns:
1906
+ Dict[str, Any]: Response containing key, value, type, ttl, createdAt, updatedAt.
1907
+
1908
+ Example Response:
1909
+ {
1910
+ "key": "state",
1911
+ "value": {"positions": 50, "orders": 10},
1912
+ "type": "object",
1913
+ "ttl": 200,
1914
+ "createdAt": "2023-10-01T10:00:00Z",
1915
+ "updatedAt": "2023-10-01T10:30:00Z"
1916
+ }
1917
+
1918
+ Raises:
1919
+ ValueError: If key is empty or invalid.
1920
+ requests.RequestException: If key not found (404) or API request fails.
1921
+
1922
+ Example:
1923
+ client.update_kv(key="portfolio_state", value={"positions": 50}, ttl=1800)
1924
+ """
1925
+ if not key or not key.strip():
1926
+ raise ValueError("Key cannot be empty or whitespace")
1927
+
1928
+ # Get strategy information
1929
+ strategy_info = self._get_strategy()
1930
+ endpoint = self._routes["kv.update"].format(strategy_id=strategy_info["id"], key=key)
1931
+
1932
+ # Build request payload
1933
+ data = {"value": value}
1934
+ if ttl is not None:
1935
+ data["ttl"] = ttl
1936
+
1937
+ logger.debug("Updating KV pair: key=%s, type=%s, ttl=%s", key, type(value).__name__, ttl)
1938
+ return self._make_request("PUT", endpoint, json=data)
1939
+
1940
+ def patch_kv(self, key: str, value: Optional[Any] = None, ttl: Optional[int] = None) -> Dict[str, Any]:
1941
+ """
1942
+ Partially update a key-value pair.
1943
+
1944
+ For OBJECT types: merges the new value with existing value.
1945
+ For other types (STRING, NUMBER, BOOLEAN, ARRAY): replaces the value entirely.
1946
+
1947
+ Args:
1948
+ key (str): The key to patch.
1949
+ value (Optional[Any]): New value or partial value to merge.
1950
+ ttl (Optional[int]): New time to live in seconds.
1951
+
1952
+ Note: At least one of value or ttl must be provided.
1953
+
1954
+ Returns:
1955
+ Dict[str, Any]: Response containing key, value, type, ttl, createdAt, updatedAt.
1956
+
1957
+ Example Response (for object merge):
1958
+ {
1959
+ "key": "state",
1960
+ "value": {"positions": 30, "orders": 5, "last_update": "2023-10-01"}, # Merged
1961
+ "type": "object",
1962
+ "ttl": 150,
1963
+ "createdAt": "2023-10-01T10:00:00Z",
1964
+ "updatedAt": "2023-10-01T10:15:00Z"
1965
+ }
1966
+
1967
+ Raises:
1968
+ ValueError: If key is empty, invalid, or no parameters provided.
1969
+ requests.RequestException: If key not found (404) or API request fails.
1970
+
1971
+ Example:
1972
+ # For objects - merges with existing
1973
+ client.patch_kv(key="portfolio_state", value={"last_update": "2023-10-01"})
1974
+
1975
+ # For non-objects - replaces entirely
1976
+ client.patch_kv(key="counter", value=42)
1977
+
1978
+ # Update only TTL
1979
+ client.patch_kv(key="session", ttl=1800)
1980
+ """
1981
+ if not key or not key.strip():
1982
+ raise ValueError("Key cannot be empty or whitespace")
1983
+
1984
+ if value is None and ttl is None:
1985
+ raise ValueError("At least one of value or ttl must be provided")
1986
+
1987
+ # Get strategy information
1988
+ strategy_info = self._get_strategy()
1989
+ endpoint = self._routes["kv.patch"].format(strategy_id=strategy_info["id"], key=key)
1990
+
1991
+ # Build request payload
1992
+ data = {}
1993
+ if value is not None:
1994
+ data["value"] = value
1995
+ if ttl is not None:
1996
+ data["ttl"] = ttl
1997
+
1998
+ logger.debug("Patching KV pair: key=%s, has_value=%s, has_ttl=%s", key, value is not None, ttl is not None)
1999
+ return self._make_request("PATCH", endpoint, json=data)
2000
+
2001
+ def delete_kv(self, key: str) -> Dict[str, Any]:
2002
+ """
2003
+ Delete a key-value pair.
2004
+
2005
+ Args:
2006
+ key (str): The key to delete.
2007
+
2008
+ Returns:
2009
+ Dict[str, Any]: Success confirmation.
2010
+
2011
+ Example Response:
2012
+ {
2013
+ "success": True,
2014
+ "message": "Key deleted successfully"
2015
+ }
2016
+
2017
+ Raises:
2018
+ ValueError: If key is empty or invalid.
2019
+ requests.RequestException: If key not found (404) or API request fails.
2020
+
2021
+ Example:
2022
+ response = client.delete_kv("old_config")
2023
+ if response["success"]:
2024
+ print("Key deleted successfully")
2025
+ """
2026
+ if not key or not key.strip():
2027
+ raise ValueError("Key cannot be empty or whitespace")
2028
+
2029
+ # Get strategy information
2030
+ strategy_info = self._get_strategy()
2031
+ endpoint = self._routes["kv.delete"].format(strategy_id=strategy_info["id"], key=key)
2032
+
2033
+ logger.debug("Deleting KV pair: key=%s", key)
2034
+ return self._make_request("DELETE", endpoint)
2035
+
2036
+ def get_all_kvs(self, page_no: int = 1, paginate: bool = False) -> List[Dict[str, Any]]:
2037
+ """
2038
+ Get all key-value pairs with their complete data.
2039
+
2040
+ Args:
2041
+ page_no (int): Page number for pagination (default: 1).
2042
+ paginate (bool): If True, automatically fetch all pages (default: False).
2043
+
2044
+ Returns:
2045
+ List[Dict[str, Any]]: List of all KV pairs with complete data.
2046
+
2047
+ Example Response:
2048
+ [
2049
+ {
2050
+ "key": "portfolio_state",
2051
+ "value": {"positions": 30},
2052
+ "type": "object",
2053
+ "ttl": 100,
2054
+ "createdAt": "2023-10-01T10:00:00Z",
2055
+ "updatedAt": "2023-10-01T10:00:00Z"
2056
+ },
2057
+ {
2058
+ "key": "environment",
2059
+ "value": "production",
2060
+ "type": "string",
2061
+ "createdAt": "2023-10-01T09:00:00Z",
2062
+ "updatedAt": "2023-10-01T09:00:00Z"
2063
+ },
2064
+ {
2065
+ "key": "trade_count",
2066
+ "value": 42,
2067
+ "type": "number",
2068
+ "createdAt": "2023-10-01T08:00:00Z",
2069
+ "updatedAt": "2023-10-01T08:30:00Z"
2070
+ }
2071
+ ]
2072
+
2073
+ Example:
2074
+ # Get first page only
2075
+ kvs = client.get_all_kvs()
2076
+
2077
+ # Get all pages automatically
2078
+ all_kvs = client.get_all_kvs(paginate=True)
2079
+ """
2080
+ # Get strategy information
2081
+ strategy_info = self._get_strategy()
2082
+ endpoint = self._routes["kv.list"].format(strategy_id=strategy_info["id"])
2083
+
2084
+ if paginate:
2085
+ return self._paginate_kv_requests(endpoint, "get_all_kvs")
2086
+ else:
2087
+ params = {"pageNo": page_no}
2088
+ logger.debug("Fetching all KVs page %d", page_no)
2089
+ return self._make_request("GET", endpoint, params=params)
2090
+
2091
+ def get_kv_keys(self, page_no: int = 1, paginate: bool = False) -> List[Dict[str, Any]]:
2092
+ """
2093
+ Get all keys with metadata (without values for memory efficiency).
2094
+
2095
+ Args:
2096
+ page_no (int): Page number for pagination (default: 1).
2097
+ paginate (bool): If True, automatically fetch all pages (default: False).
2098
+
2099
+ Returns:
2100
+ List[Dict[str, Any]]: List of keys with metadata (no values).
2101
+
2102
+ Example Response:
2103
+ [
2104
+ {
2105
+ "key": "portfolio_state",
2106
+ "type": "object",
2107
+ "ttl": 100,
2108
+ "createdAt": "2023-10-01T10:00:00Z",
2109
+ "updatedAt": "2023-10-01T10:00:00Z"
2110
+ },
2111
+ {
2112
+ "key": "environment",
2113
+ "type": "string",
2114
+ "createdAt": "2023-10-01T09:00:00Z",
2115
+ "updatedAt": "2023-10-01T09:00:00Z"
2116
+ },
2117
+ {
2118
+ "key": "trade_count",
2119
+ "type": "number",
2120
+ "createdAt": "2023-10-01T08:00:00Z",
2121
+ "updatedAt": "2023-10-01T08:30:00Z"
2122
+ }
2123
+ ]
2124
+
2125
+ Example:
2126
+ # Get keys for first page
2127
+ keys = client.get_kv_keys()
2128
+
2129
+ # Get all keys across all pages
2130
+ all_keys = client.get_kv_keys(paginate=True)
2131
+
2132
+ # Check what keys exist
2133
+ for key_info in all_keys:
2134
+ print(f"Key: {key_info['key']}, Type: {key_info['type']}")
2135
+ """
2136
+ # Get strategy information
2137
+ strategy_info = self._get_strategy()
2138
+ endpoint = self._routes["kv.keys"].format(strategy_id=strategy_info["id"])
2139
+
2140
+ if paginate:
2141
+ return self._paginate_kv_requests(endpoint, "get_kv_keys")
2142
+ else:
2143
+ params = {"pageNo": page_no}
2144
+ logger.debug("Fetching KV keys page %d", page_no)
2145
+ return self._make_request("GET", endpoint, params=params)
2146
+
2147
+ def _paginate_kv_requests(self, endpoint: str, operation: str) -> List[Dict[str, Any]]:
2148
+ """
2149
+ Internal method to handle pagination for KV list operations.
2150
+
2151
+ Args:
2152
+ endpoint (str): API endpoint.
2153
+ operation (str): Operation name for logging.
2154
+
2155
+ Returns:
2156
+ List[Dict[str, Any]]: Combined results from all pages.
2157
+ """
2158
+ all_items = []
2159
+ page_no = 1
2160
+ total_count = None
2161
+ page_size = 20 # KV API uses 20 items per page
2162
+
2163
+ while True:
2164
+ params = {"pageNo": page_no}
2165
+ logger.debug("Fetching %s page %d", operation, page_no)
2166
+
2167
+ try:
2168
+ url = f"{self.base_url}{endpoint}"
2169
+ response = requests.request(
2170
+ method="GET",
2171
+ url=url,
2172
+ headers=self.headers,
2173
+ params=params
2174
+ )
2175
+ response.raise_for_status()
2176
+
2177
+ # Get items from the current page
2178
+ items = response.json()
2179
+ all_items.extend(items)
2180
+
2181
+ # Check if we need to fetch more pages
2182
+ if total_count is None and "X-Total-Count" in response.headers:
2183
+ try:
2184
+ total_count = int(response.headers["X-Total-Count"])
2185
+ logger.debug("Total %s count: %d", operation, total_count)
2186
+ except (ValueError, TypeError):
2187
+ logger.warning("Could not parse X-Total-Count header for %s", operation)
2188
+ break
2189
+
2190
+ # If we've fetched all items or there are no more pages, stop
2191
+ if not items or len(all_items) >= total_count or total_count is None:
2192
+ break
2193
+
2194
+ # Move to the next page
2195
+ page_no += 1
2196
+
2197
+ except requests.RequestException as e:
2198
+ logger.error("API request failed during %s pagination: %s", operation, e, exc_info=True)
2199
+ if hasattr(e.response, 'text'):
2200
+ logger.error("Response content: %s", e.response.text)
2201
+ raise
2202
+
2203
+ logger.info("Fetched %d items in total for %s", len(all_items), operation)
2204
+ return all_items
2205
+
2206
+ # Add this method to the WizzerClient class
2207
+ def delete_all_kv(self) -> Dict[str, Any]:
2208
+ """
2209
+ Delete all key-value pairs for the current strategy.
2210
+
2211
+ This method removes all KV pairs associated with the client's strategy.
2212
+ Use with caution as this operation cannot be undone.
2213
+
2214
+ Returns:
2215
+ Dict[str, Any]: Response containing success status, count of deleted items, and message.
2216
+
2217
+ Example Response:
2218
+ {
2219
+ "success": True,
2220
+ "deleted": 15,
2221
+ "message": "Successfully deleted 15 key-value pairs"
2222
+ }
2223
+
2224
+ Raises:
2225
+ requests.RequestException: If API request fails.
2226
+
2227
+ Example:
2228
+ response = client.delete_all_kv()
2229
+ print(f"Deleted {response['deleted']} key-value pairs")
2230
+ """
2231
+ # Get strategy information
2232
+ strategy_info = self._get_strategy()
2233
+ endpoint = self._routes["kv.delete_all"].format(strategy_id=strategy_info["id"])
2234
+
2235
+ logger.debug("Deleting all KV pairs for strategy: %s", strategy_info["id"])
2236
+ return self._make_request("DELETE", endpoint)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wiz_trader
3
- Version: 0.34.0
3
+ Version: 0.35.0
4
4
  Summary: A Python SDK for connecting to the Wizzer.
5
5
  Home-page: https://bitbucket.org/wizzer-tech/quotes_sdk.git
6
6
  Author: Pawan Wagh
@@ -3663,3 +3663,243 @@ results = client.run_screener(
3663
3663
  limit=10
3664
3664
  )
3665
3665
  ```
3666
+
3667
+ ## KV Store Integration
3668
+
3669
+ The WizzerClient includes comprehensive Key-Value (KV) store functionality for persistent data management. This feature allows you to store configuration data, state information, user preferences, and other persistent data associated with your trading strategies.
3670
+
3671
+ ### Supported Data Types
3672
+
3673
+ The KV store supports all JSON-serializable data types:
3674
+
3675
+ - **STRING**: Text values (`"production"`, `"user123"`)
3676
+ - **NUMBER**: Integer and float values (`42`, `150.25`)
3677
+ - **BOOLEAN**: True/false values (`True`, `False`)
3678
+ - **ARRAY**: Lists of values (`["AAPL", "GOOGL", "MSFT"]`)
3679
+ - **OBJECT**: Dictionaries/objects (`{"positions": 30, "cash": 50000}`)
3680
+
3681
+ ### Available Constants
3682
+
3683
+ ```python
3684
+ client.KV_TYPE_STRING # "string"
3685
+ client.KV_TYPE_NUMBER # "number"
3686
+ client.KV_TYPE_BOOLEAN # "boolean"
3687
+ client.KV_TYPE_ARRAY # "array"
3688
+ client.KV_TYPE_OBJECT # "object"
3689
+ ```
3690
+
3691
+ ### Core CRUD Operations
3692
+
3693
+ #### Create Key-Value Pair
3694
+
3695
+ ```python
3696
+ # Store different data types
3697
+ client.create_kv("environment", "production")
3698
+ client.create_kv("trade_count", 42)
3699
+ client.create_kv("is_active", True)
3700
+ client.create_kv("symbols", ["AAPL", "GOOGL", "MSFT"])
3701
+
3702
+ # Store complex configuration with TTL (expires in 1 hour)
3703
+ config = {
3704
+ "risk_level": "medium",
3705
+ "max_positions": 10,
3706
+ "stop_loss_pct": 0.05,
3707
+ "take_profit_pct": 0.15
3708
+ }
3709
+ client.create_kv("strategy_config", config, ttl=3600)
3710
+ ```
3711
+
3712
+ #### Retrieve Key-Value Pair
3713
+
3714
+ ```python
3715
+ # Get a single KV pair
3716
+ data = client.get_kv("strategy_config")
3717
+ print(data["value"]) # The stored object
3718
+ print(data["type"]) # "object"
3719
+ print(data["ttl"]) # Remaining time to live (if set)
3720
+
3721
+ # Access nested values
3722
+ risk_level = data["value"]["risk_level"] # "medium"
3723
+ ```
3724
+
3725
+ #### Update Key-Value Pair (Complete Replacement)
3726
+
3727
+ ```python
3728
+ # Complete replacement of existing key
3729
+ new_config = {"risk_level": "high", "max_positions": 5}
3730
+ client.update_kv("strategy_config", new_config, ttl=1800)
3731
+ ```
3732
+
3733
+ #### Patch Key-Value Pair (Partial Update)
3734
+
3735
+ ```python
3736
+ # For objects - merges with existing data
3737
+ client.patch_kv("strategy_config", {"last_updated": "2024-01-15"})
3738
+
3739
+ # For non-objects - replaces entirely
3740
+ client.patch_kv("trade_count", 50)
3741
+
3742
+ # Update only TTL
3743
+ client.patch_kv("strategy_config", ttl=7200)
3744
+ ```
3745
+
3746
+ #### Delete Key-Value Pair
3747
+
3748
+ ```python
3749
+ response = client.delete_kv("old_config")
3750
+ if response["success"]:
3751
+ print("Key deleted successfully")
3752
+ ```
3753
+
3754
+ ### List Operations
3755
+
3756
+ #### Get All KV Pairs (with values)
3757
+
3758
+ ```python
3759
+ # Get first page (20 items)
3760
+ kvs = client.get_all_kvs(page_no=1)
3761
+
3762
+ # Get all pages automatically
3763
+ all_kvs = client.get_all_kvs(paginate=True)
3764
+
3765
+ for kv in all_kvs:
3766
+ print(f"Key: {kv['key']}")
3767
+ print(f"Type: {kv['type']}")
3768
+ print(f"Value: {kv['value']}")
3769
+ ```
3770
+
3771
+ #### Get Keys Only (memory efficient)
3772
+
3773
+ ```python
3774
+ # Get all keys without values (faster for large datasets)
3775
+ keys = client.get_kv_keys(paginate=True)
3776
+
3777
+ for key_info in keys:
3778
+ print(f"Key: {key_info['key']}, Type: {key_info['type']}")
3779
+ if 'ttl' in key_info:
3780
+ print(f" TTL: {key_info['ttl']} seconds remaining")
3781
+ ```
3782
+
3783
+ ### Advanced Usage Examples
3784
+
3785
+ #### Strategy Configuration Management
3786
+
3787
+ ```python
3788
+ # Store strategy parameters
3789
+ params = {
3790
+ "moving_average_period": 20,
3791
+ "rsi_oversold": 30,
3792
+ "rsi_overbought": 70,
3793
+ "position_size": 0.02
3794
+ }
3795
+ client.create_kv("strategy_params", params)
3796
+
3797
+ # Update specific parameters using patch (merges with existing)
3798
+ client.patch_kv("strategy_params", {"moving_average_period": 50})
3799
+ ```
3800
+
3801
+ #### State Persistence
3802
+
3803
+ ```python
3804
+ # Save current portfolio state
3805
+ portfolio_state = {
3806
+ "cash_balance": 50000,
3807
+ "open_positions": 5,
3808
+ "daily_pnl": 1250.75,
3809
+ "last_updated": "2024-01-15T15:30:00Z"
3810
+ }
3811
+ client.create_kv("portfolio_state", portfolio_state, ttl=3600)
3812
+
3813
+ # Update state periodically
3814
+ client.patch_kv("portfolio_state", {
3815
+ "daily_pnl": 1500.25,
3816
+ "last_updated": "2024-01-15T16:00:00Z"
3817
+ })
3818
+ ```
3819
+
3820
+ #### Feature Flags
3821
+
3822
+ ```python
3823
+ # Enable/disable features dynamically
3824
+ features = {
3825
+ "advanced_charts": True,
3826
+ "paper_trading": True,
3827
+ "options_trading": False,
3828
+ "algo_trading": True
3829
+ }
3830
+ client.create_kv("feature_flags", features)
3831
+
3832
+ # Toggle a feature
3833
+ client.patch_kv("feature_flags", {"options_trading": True})
3834
+ ```
3835
+
3836
+ #### Data Caching with TTL
3837
+
3838
+ ```python
3839
+ # Cache market data with short TTL (5 minutes)
3840
+ market_status = {
3841
+ "nse_open": True,
3842
+ "bse_open": True,
3843
+ "last_checked": "2024-01-15T09:15:00Z"
3844
+ }
3845
+ client.create_kv("market_status", market_status, ttl=300)
3846
+ ```
3847
+
3848
+ ### Object Merge Behavior
3849
+
3850
+ For OBJECT type data, the `patch_kv` method performs intelligent merging:
3851
+
3852
+ ```python
3853
+ # Initial object
3854
+ client.create_kv("user_prefs", {
3855
+ "theme": "dark",
3856
+ "notifications": True,
3857
+ "language": "en"
3858
+ })
3859
+
3860
+ # Patch merges new fields with existing ones
3861
+ client.patch_kv("user_prefs", {
3862
+ "notifications": False, # Updates existing field
3863
+ "timezone": "UTC" # Adds new field
3864
+ })
3865
+
3866
+ # Result: {"theme": "dark", "notifications": False, "language": "en", "timezone": "UTC"}
3867
+ ```
3868
+
3869
+ ### Delete All KV Pairs
3870
+
3871
+ The `delete_all_kv` method allows you to remove all key-value pairs for a strategy at once:
3872
+
3873
+ ```python
3874
+ # Delete all KV pairs for the current strategy
3875
+ response = client.delete_all_kv()
3876
+ print(f"Deleted {response['deleted']} key-value pairs")
3877
+
3878
+ # Example response:
3879
+ # {
3880
+ # "success": True,
3881
+ # "deleted": 15,
3882
+ # "message": "Successfully deleted 15 key-value pairs"
3883
+ # }
3884
+
3885
+ # Common usage - reset strategy state before reinitialization
3886
+ def reset_strategy_state():
3887
+ """Reset all persistent state for the strategy."""
3888
+ # Clear all existing KV pairs
3889
+ result = client.delete_all_kv()
3890
+ print(f"Cleared {result['deleted']} KV pairs")
3891
+
3892
+ # Reinitialize with default configuration
3893
+ client.create_kv("config", {
3894
+ "mode": "production",
3895
+ "risk_percentage": 0.02,
3896
+ "max_positions": 10
3897
+ })
3898
+ client.create_kv("state", {
3899
+ "initialized": True,
3900
+ "start_time": datetime.now().isoformat()
3901
+ })
3902
+ print("Strategy state reset successfully")
3903
+
3904
+ # Use with caution - this operation cannot be undone!
3905
+ ```
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=mvDJsObXpYGcnLwfpMITtZeAouMb_YHNW0Tqse0V0bg,183
2
+ wiz_trader/apis/__init__.py,sha256=6sUr1nzmplNdld0zryMrQSt0jHT2GhOiFYgKKVHzk8U,133
3
+ wiz_trader/apis/client.py,sha256=znwlyDIHbaiQuDqxp7pn1NPiiYB99oA74JWt4AiLkBg,80088
4
+ wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
+ wiz_trader/quotes/client.py,sha256=aZ5LVlrj0mKfgHgFxERmk2HDZraB6RMaormTOMlqWZc,14915
6
+ wiz_trader-0.35.0.dist-info/METADATA,sha256=0aBskcZN4xpphpCtQMO9oAYIjwgboe9nmcpcywuKrXg,144695
7
+ wiz_trader-0.35.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ wiz_trader-0.35.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.35.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- wiz_trader/__init__.py,sha256=Bd8yqFEqK9MNrzHUVgrbEntlyIHZhArgA6AZT9SEFjY,183
2
- wiz_trader/apis/__init__.py,sha256=6sUr1nzmplNdld0zryMrQSt0jHT2GhOiFYgKKVHzk8U,133
3
- wiz_trader/apis/client.py,sha256=WzsKxrNi9T-xbtXWBT2J41bJ-sz0KsGFYV5Oyddo3gg,65487
4
- wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
- wiz_trader/quotes/client.py,sha256=aZ5LVlrj0mKfgHgFxERmk2HDZraB6RMaormTOMlqWZc,14915
6
- wiz_trader-0.34.0.dist-info/METADATA,sha256=OAi5g0xbSdp9bc-F1Fgl7d8oMRIsfimTohtJ0oA-FX0,138653
7
- wiz_trader-0.34.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- wiz_trader-0.34.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
- wiz_trader-0.34.0.dist-info/RECORD,,