feat: add fetch_latest_closed_rates_indexed and allow_whole_dollar_env opt-in (#45)
* feat: add fetch_latest_closed_rates_indexed and allow_whole_dollar_env opt-in (#43, #44) Closes #43: add fetch_latest_closed_rates_indexed(client, *, symbol, granularity, count) -> pd.DataFrame to mt5cli/trading.py. Internally reuses fetch_latest_closed_rates_for_trading_client(), converts the "time" column to a UTC-aware DatetimeIndex named "time", and drops the original column. Exported from trading.__all__, mt5cli.__init__, and STABLE_SDK_EXPORTS. Closes #44: extend substitute_env_placeholders() with opt-in allow_whole_dollar_env=False that expands whole-value $ENV_NAME strings (entire string must be exactly $IDENTIFIER). Threaded through build_config(), resolve_account_spec(), and resolve_account_specs() with the same default=False. Partial strings like "plan$pass", "abc$ENV", or "$ENV-suffix" are never expanded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: align Markdown table columns in docs and skill file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: treat numeric (float64) epoch seconds as UTC in _rate_time_to_utc After DataFrame concat or NA upcast the time column becomes float64, which is still epoch seconds. Using is_numeric_dtype instead of is_integer_dtype fixes the silent misalignment. Using series.to_numpy() before passing to pd.to_datetime avoids the redundant pd.DatetimeIndex() wrapper and aligns with how existing rate-time normalization in schemas.py handles numeric timestamps. Add test_converts_float_epoch_seconds_to_utc_datetime_index to cover the regression. Add a doc note clarifying that build_config cannot expand login since that parameter is int | None. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: reject NaT values after rate timestamp conversion in _rate_time_to_utc pd.to_datetime() silently produces NaT for None/NaN inputs rather than raising, so the function could return a DatetimeIndex containing NaT despite documenting invalid timestamps as a ValueError. Check any(idx.isna()) after conversion and raise with a clear message. Add test_raises_on_nat_time_column to cover the regression. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Bump version to v0.9.0 * fix: handle object numeric rate timestamps --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -86,6 +86,28 @@ resolved = resolve_account_specs(accounts, server="Broker-Demo")
|
||||
# resolved[0].login == "12345", resolved[0].server == "Broker-Demo"
|
||||
```
|
||||
|
||||
Pass `allow_whole_dollar_env=True` to also expand strings whose **entire value**
|
||||
is a bare `$ENV_NAME` identifier (no braces). This opt-in covers
|
||||
`substitute_env_placeholders()`, `resolve_account_spec()`,
|
||||
`resolve_account_specs()`, and `build_config()`. Note: `build_config` cannot
|
||||
expand `login` because that parameter is `int | None`; use
|
||||
`resolve_account_spec` for a string `login` placeholder. Partial strings such as
|
||||
`"plan$pass"`, `"abc$ENV"`, or `"$ENV-suffix"` are never expanded — only an
|
||||
exact `$IDENTIFIER` whole-string match qualifies. The default is `False` to
|
||||
preserve backward compatibility.
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from mt5cli import AccountSpec, resolve_account_specs
|
||||
|
||||
os.environ["MT5_PASSWORD"] = "secret"
|
||||
accounts = [AccountSpec(symbols=["EURUSD"], password="$MT5_PASSWORD")]
|
||||
|
||||
resolved = resolve_account_specs(accounts, allow_whole_dollar_env=True)
|
||||
# resolved[0].password == "secret"
|
||||
```
|
||||
|
||||
### Throttled incremental history updates
|
||||
|
||||
`ThrottledHistoryUpdater` wraps `update_history()` with a minimum interval
|
||||
|
||||
Reference in New Issue
Block a user