onesecondtrader 0.12.0__tar.gz → 0.13.0__tar.gz

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.
Files changed (21) hide show
  1. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/PKG-INFO +1 -1
  2. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/pyproject.toml +1 -1
  3. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/core/models.py +27 -6
  4. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/indicators/base_indicator.py +18 -19
  5. onesecondtrader-0.13.0/src/onesecondtrader/indicators/moving_averages.py +132 -0
  6. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/LICENSE +0 -0
  7. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/README.md +0 -0
  8. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/__init__.py +0 -0
  9. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/core/__init__.py +0 -0
  10. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/core/py.typed +0 -0
  11. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/datafeeds/__init__.py +0 -0
  12. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/datafeeds/base_datafeed.py +0 -0
  13. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/datafeeds/csv_datafeed.py +0 -0
  14. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/indicators/__init__.py +0 -0
  15. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/messaging/__init__.py +0 -0
  16. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/messaging/eventbus.py +0 -0
  17. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/messaging/events.py +0 -0
  18. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/monitoring/__init__.py +0 -0
  19. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/monitoring/console.py +0 -0
  20. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/monitoring/py.typed +0 -0
  21. {onesecondtrader-0.12.0 → onesecondtrader-0.13.0}/src/onesecondtrader/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onesecondtrader
3
- Version: 0.12.0
3
+ Version: 0.13.0
4
4
  Summary: The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place.
5
5
  License-File: LICENSE
6
6
  Author: Nils P. Kujath
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "onesecondtrader"
3
- version = "0.12.0"
3
+ version = "0.13.0"
4
4
  description = "The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place."
5
5
  authors = [
6
6
  {name = "Nils P. Kujath",email = "63961429+NilsKujath@users.noreply.github.com"}
@@ -63,8 +63,7 @@ class TimeInForce(enum.Enum):
63
63
  | `FOK` | `enum.auto()` | Fill entire order immediately or cancel (Fill-or-Kill) |
64
64
  | `GTC` | `enum.auto()` | Active until explicitly cancelled (Good-Till-Cancelled) |
65
65
  | `GTD` | `enum.auto()` | Active until specified date (Good-Till-Date) |
66
- | `IOC` | `enum.auto()` | Execute available quantity immediately, cancel rest
67
- (Immediate-or-Cancel) |
66
+ | `IOC` | `enum.auto()` | Execute available quantity immediately, cancel rest (Immediate-or-Cancel) |
68
67
  """
69
68
 
70
69
  DAY = enum.auto()
@@ -102,10 +101,8 @@ class OrderLifecycleState(enum.Enum):
102
101
 
103
102
  | Enum | Value | Description |
104
103
  |------|-------|-------------|
105
- | `PENDING` | `enum.auto()` | Order has been submitted, but not yet acknowledged by
106
- the broker |
107
- | `OPEN` | `enum.auto()` | Order has been acknowledged by the broker, but not yet
108
- filled or cancelled |
104
+ | `PENDING` | `enum.auto()` | Order has been submitted, but not yet acknowledged by the broker |
105
+ | `OPEN` | `enum.auto()` | Order has been acknowledged by the broker, but not yet filled or cancelled |
109
106
  | `FILLED` | `enum.auto()` | Order has been filled |
110
107
  | `CANCELLED` | `enum.auto()` | Order has been cancelled |
111
108
  """
@@ -165,3 +162,27 @@ class RecordType(enum.Enum):
165
162
  return "daily bars"
166
163
  case _:
167
164
  return f"unknown ({rtype})"
165
+
166
+
167
+ class XMAMode(enum.Enum):
168
+ """
169
+ Enum for moving average modes.
170
+
171
+ **Attributes:**
172
+
173
+ | Enum | Value | Description |
174
+ |------|-------|-------------|
175
+ | `OPEN` | `enum.auto()` | Open price |
176
+ | `HIGH` | `enum.auto()` | High price |
177
+ | `LOW` | `enum.auto()` | Low price |
178
+ | `CLOSE` | `enum.auto()` | Close price |
179
+ | `TYPICAL_PRICE` | `enum.auto()` | Typical price ((H+ L + C) / 3) |
180
+ | `WEIGHTED_CLOSE` | `enum.auto()` | Weighted close price ((H + L + 2*C) / 4) |
181
+ """
182
+
183
+ OPEN = enum.auto()
184
+ HIGH = enum.auto()
185
+ LOW = enum.auto()
186
+ CLOSE = enum.auto()
187
+ TYPICAL_PRICE = enum.auto()
188
+ WEIGHTED_CLOSE = enum.auto()
@@ -16,8 +16,7 @@ class BaseIndicator(abc.ABC):
16
16
  Base class for all indicators.
17
17
 
18
18
  If new market data is received, the indicator is updated by calling the
19
- `<indicator_instance>.update(incoming_bar)` method.
20
-
19
+ `update(incoming_bar)` method.
21
20
  When programming a new indicator, only the `name` property and the
22
21
  `_compute_indicator()` method need to be implemented.
23
22
 
@@ -84,6 +83,15 @@ class BaseIndicator(abc.ABC):
84
83
  """
85
84
  pass
86
85
 
86
+ @property
87
+ def latest(self) -> float:
88
+ """
89
+ The latest (most recent) indicator value.
90
+
91
+ Equivalent to self[0]. Returns numpy.nan when no value is available yet.
92
+ """
93
+ return self[0]
94
+
87
95
  def update(self, incoming_bar: models.Bar) -> None:
88
96
  """
89
97
  Updates the indicator based on an incoming closed bar by calling
@@ -93,6 +101,14 @@ class BaseIndicator(abc.ABC):
93
101
  with self._lock:
94
102
  self._history.append(new_value)
95
103
 
104
+ @abc.abstractmethod
105
+ def _compute_indicator(self, incoming_bar: models.Bar) -> float:
106
+ """
107
+ Computes the new indicator value based on an incoming closed bar.
108
+ This method must be implemented by subclasses.
109
+ """
110
+ pass
111
+
96
112
  def __getitem__(self, index: int) -> float:
97
113
  """
98
114
  Return the indicator value at the given index with tolerant indexing.
@@ -118,20 +134,3 @@ class BaseIndicator(abc.ABC):
118
134
  return self._history[normalized]
119
135
  except IndexError:
120
136
  return np.nan
121
-
122
- @property
123
- def latest(self) -> float:
124
- """
125
- The latest (most recent) indicator value.
126
-
127
- Equivalent to self[0]. Returns numpy.nan when no value is available yet.
128
- """
129
- return self[0]
130
-
131
- @abc.abstractmethod
132
- def _compute_indicator(self, incoming_bar: models.Bar) -> float:
133
- """
134
- Computes the new indicator value based on an incoming closed bar.
135
- This method must be implemented by subclasses.
136
- """
137
- pass
@@ -0,0 +1,132 @@
1
+ """
2
+ This module provides various moving average indicators.
3
+ """
4
+
5
+ import numpy as np
6
+ import collections
7
+ from onesecondtrader.indicators import base_indicator
8
+ from onesecondtrader.core import models
9
+ from onesecondtrader.monitoring import console
10
+
11
+
12
+ class SimpleMovingAverage(base_indicator.BaseIndicator):
13
+ """
14
+ Simple Moving Average (SMA) indicator for different OHLC-data related time series,
15
+ the possible modes for the SMA calculation are indicated in the
16
+ `core.models.XMAMode` enum (currently: `open`, `high`, `low`, `close`,
17
+ `typical_price`, `weighted close`).
18
+
19
+ Examples:
20
+ >>> from onesecondtrader.indicators import moving_averages
21
+ >>> from onesecondtrader.core import models
22
+ >>> sma = moving_averages.SimpleMovingAverage(
23
+ ... period=3, mode=models.XMAMode.CLOSE
24
+ ... )
25
+ >>> bar1 = models.Bar(
26
+ ... open=100.0, high=101.0, low=99.0, close=100.0, volume=1000
27
+ ... )
28
+ >>> sma.update(bar1)
29
+ >>> import numpy as np
30
+ >>> np.isnan(sma.latest)
31
+ True
32
+ >>> bar2 = models.Bar(
33
+ ... open=100.0, high=102.0, low=100.0, close=101.0, volume=1500
34
+ ... )
35
+ >>> sma.update(bar2)
36
+ >>> np.isnan(sma.latest)
37
+ True
38
+ >>> bar3 = models.Bar(
39
+ ... open=101.0, high=103.0, low=101.0, close=102.0, volume=2000
40
+ ... )
41
+ >>> sma.update(bar3)
42
+ >>> np.isnan(sma.latest)
43
+ False
44
+ >>> sma.latest
45
+ 101.0
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ period: int,
51
+ mode: models.XMAMode = models.XMAMode.CLOSE,
52
+ max_history: int = 100,
53
+ ) -> None:
54
+ """
55
+ Initialize the indicator with a period and a mode.
56
+
57
+ Args:
58
+ period (int): Period of the moving average. Will be set to 1 if < 1.
59
+ mode (models.XMAMode): Mode of the moving average. Defaults to `CLOSE`.
60
+ max_history (int): Maximum lookback history length. Defaults to 100.
61
+
62
+ Attributes:
63
+ self.period (int): Period of the moving average.
64
+ self.mode (models.XMAMode): Mode of the moving average.
65
+ """
66
+ if period < 1:
67
+ console.logger.warning(
68
+ f"Period must be >= 1, got {period}; defaulting to 1"
69
+ )
70
+ period = 1
71
+
72
+ super().__init__(max_history=max_history)
73
+ self.period: int = period
74
+ self.mode: models.XMAMode = mode
75
+ self._window: collections.deque[float] = collections.deque(maxlen=self.period)
76
+
77
+ @property
78
+ def name(self) -> str:
79
+ return f"SMA_{self.period}_{self.mode.name}"
80
+
81
+ def _compute_indicator(self, incoming_bar: models.Bar) -> float:
82
+ """
83
+ Compute the specified simple moving average based on the incoming bar.
84
+
85
+ Args:
86
+ incoming_bar (models.Bar): Incoming bar with OHLCV data.
87
+
88
+ Returns:
89
+ float: Simple moving average value, or np.nan if insufficient data or
90
+ errors occur.
91
+ """
92
+ try:
93
+ mode = self.mode
94
+ if mode is models.XMAMode.OPEN:
95
+ current_value = incoming_bar.open
96
+ elif mode is models.XMAMode.HIGH:
97
+ current_value = incoming_bar.high
98
+ elif mode is models.XMAMode.LOW:
99
+ current_value = incoming_bar.low
100
+ elif mode is models.XMAMode.CLOSE:
101
+ current_value = incoming_bar.close
102
+ elif mode is models.XMAMode.TYPICAL_PRICE:
103
+ current_value = (
104
+ incoming_bar.high + incoming_bar.low + incoming_bar.close
105
+ ) / 3.0
106
+ elif mode is models.XMAMode.WEIGHTED_CLOSE:
107
+ current_value = (
108
+ incoming_bar.high + incoming_bar.low + 2.0 * incoming_bar.close
109
+ ) / 4.0
110
+ else:
111
+ console.logger.warning(
112
+ f"Unsupported XMAMode: {mode}; using close price"
113
+ )
114
+ current_value = incoming_bar.close
115
+
116
+ if not np.isfinite(current_value):
117
+ console.logger.warning(
118
+ f"Invalid value extracted: {current_value} (mode={mode.name}); "
119
+ f"using np.nan"
120
+ )
121
+ return np.nan
122
+
123
+ with self._lock:
124
+ self._window.append(current_value)
125
+ if len(self._window) < self.period:
126
+ return np.nan
127
+ sma_value = sum(self._window) / self.period
128
+ return sma_value
129
+
130
+ except Exception as e:
131
+ console.logger.warning(f"SMA calculation failed: {e}; returning np.nan")
132
+ return np.nan