Bug: Error printing stats starting at Sortino Ratio
- Dominant language
- Python
- Stars
- 9k
- Forks
- 1.5k
- PR merge metrics
- No merged PRs in 30d
Description
### Expected behavior
Hello,
For many values of my strategies I have to limit my stats ouptut to the first 12 lines `stats.head(12`)` or I get an error. I guess this is related to `Sortino Ratio` display which is the next row which should appear. Maybe it can't be computed for some input values and its output is 'Ǹan'
I have no problem with plotting
I can send you the code whether required.
Thanks for your help
### Code sample
```python
```
### Actual behavior
```
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:770, in PlainTextFormatter.__call__(self, obj)
[763](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:763) stream = StringIO()
[764](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:764) printer = pretty.RepresentationPrinter(stream, self.verbose,
[765](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:765) self.max_width, self.newline,
[766](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:766) max_seq_length=self.max_seq_length,
[767](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:767) singleton_pprinters=self.singleton_printers,
[768](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:768) type_pprinters=self.type_printers,
[769](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:769) deferred_pprinters=self.deferred_printers)
--> [770](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:770) printer.pretty(obj)
[771](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:771) printer.flush()
[772](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/core/formatters.py:772) return stream.getvalue()
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:419, in RepresentationPrinter.pretty(self, obj)
[408](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:408) return meth(obj, self, cycle)
[409](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:409) if (
[410](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:410) cls is not object
[411](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:411) # check if cls defines __repr__
(...)
[417](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:417) and callable(_safe_getattr(cls, "__repr__", None))
[418](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:418) ):
--> [419](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:419) return _repr_pprint(obj, self, cycle)
[421](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:421) return _default_pprint(obj, self, cycle)
[422](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:422) finally:
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:794, in _repr_pprint(obj, p, cycle)
[792](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:792) """A pprint that just redirects to the normal repr function."""
[793](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:793) # Find newlines and replace them with p.break_()
--> [794](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:794) output = repr(obj)
[795](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:795) lines = output.splitlines()
[796](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/IPython/lib/pretty.py:796) with p.group():
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:196, in _Stats.__repr__(self)
[189](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:189) def __repr__(self):
[190](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:190) with pd.option_context(
[191](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:191) 'display.max_colwidth', 20, # Prevent expansion due to _equity and _trades dfs
[192](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:192) 'display.max_rows', len(self), # Reveal self whole
[193](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:193) 'display.precision', 5, # Enough for my eyes at least
[194](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:194) # 'format.na_rep', '--', # TODO: Enable once it works
[195](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:195) ):
--> [196](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/backtesting/_stats.py:196) return super().__repr__()
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1784, in Series.__repr__(self)
[1782](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1782) # pylint: disable=invalid-repr-returned
[1783](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1783) repr_params = fmt.get_series_repr_params()
-> [1784](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1784) return self.to_string(**repr_params)
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1883, in Series.to_string(self, buf, na_rep, float_format, header, index, length, dtype, name, max_rows, min_rows)
[1831](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1831) """
[1832](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1832) Render a string representation of the Series.
[1833](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1833)
(...)
[1869](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1869) '0 1\\n1 2\\n2 3'
[1870](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1870) """
[1871](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1871) formatter = fmt.SeriesFormatter(
[1872](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1872) self,
[1873](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1873) name=name,
(...)
[1881](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1881) max_rows=max_rows,
[1882](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1882) )
-> [1883](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1883) result = formatter.to_string()
[1885](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1885) # catch contract violations
[1886](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/core/series.py:1886) if not isinstance(result, str):
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:320, in SeriesFormatter.to_string(self)
[318](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:318) else:
[319](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:319) fmt_index = index._format_flat(include_name=True)
--> [320](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:320) fmt_values = self._get_formatted_values()
[322](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:322) if self.is_truncated_vertically:
[323](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:323) n_header_rows = 0
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:297, in SeriesFormatter._get_formatted_values(self)
[296](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:296) def _get_formatted_values(self) -> list[str]:
--> [297](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:297) return format_array(
[298](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:298) self.tr_series._values,
[299](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:299) None,
[300](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:300) float_format=self.float_format,
[301](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:301) na_rep=self.na_rep,
[302](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:302) leading_space=self.index,
[303](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:303) )
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1161, in format_array(values, formatter, float_format, na_rep, digits, space, justify, decimal, leading_space, quoting, fallback_formatter)
[1145](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1145) digits = get_option("display.precision")
[1147](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1147) fmt_obj = fmt_klass(
[1148](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1148) values,
[1149](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1149) digits=digits,
(...)
[1158](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1158) fallback_formatter=fallback_formatter,
[1159](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1159) )
-> [1161](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1161) return fmt_obj.get_result()
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1195, in _GenericArrayFormatter.get_result(self)
[1193](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1193) def get_result(self) -> list[str]:
[1194](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1194) fmt_values = self._format_strings()
-> [1195](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1195) return _make_fixed_width(fmt_values, self.justify)
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1740, in _make_fixed_width(strings, justify, minimum, adj)
[1737](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1737) else:
[1738](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1738) adjustment = adj
-> [1740](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1740) max_len = max(adjustment.len(x) for x in strings)
[1742](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1742) if minimum is not None:
[1743](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1743) max_len = max(minimum, max_len)
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1740, in (.0)
[1737](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1737) else:
[1738](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1738) adjustment = adj
-> [1740](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1740) max_len = max(adjustment.len(x) for x in strings)
[1742](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1742) if minimum is not None:
[1743](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/format.py:1743) max_len = max(minimum, max_len)
File /opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/printing.py:511, in _TextAdjustment.len(self, text)
[510](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/printing.py:510) def len(self, text: str) -> int:
--> [511](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/quants-lab/lib/python3.10/site-packages/pandas/io/formats/printing.py:511) return len(text)
TypeError: object of type 'NoneType' has no len()
```
### Additional info, steps to reproduce, full crash traceback, screenshots
_No response_
### Software versions
- backtesting 0.6.3
- Debian 12
Contributor guide
Research direction
Start in backtesting/_stats.py at _Stats.__repr__ and reproduce the failure when displaying stats beyond the first 12 rows, especially around Sortino Ratio. Inspect how the Series is rendered through pandas and compare inputs that produce the reported NaN output. Done means full stats display completes without the TypeError for the affected strategy values.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- pandas, python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 42/100