Skip to content

Commit 6bd7492

Browse files
committed
Refactor f-string formating.
1 parent 5dc447f commit 6bd7492

File tree

2 files changed

+28
-35
lines changed

2 files changed

+28
-35
lines changed

backtesting/_plotting.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ def _maybe_resample_data(resample_rule, df, indicators, equity_data, trades):
101101
FREQS = ('1T', '5T', '10T', '15T', '30T', '1H', '2H', '4H', '8H', '1D', '1W', '1M')
102102
freq = next((f for f in FREQS[from_index:]
103103
if len(df.resample(f)) <= _MAX_CANDLES), FREQS[-1])
104-
warnings.warn("Data contains too many candlesticks to plot; downsampling to {!r}. "
105-
"See `Backtest.plot(resample=...)`".format(freq))
104+
warnings.warn(f"Data contains too many candlesticks to plot; downsampling to {freq!r}. "
105+
"See `Backtest.plot(resample=...)`")
106106

107107
from .lib import OHLCV_AGG, TRADES_AGG, _EQUITY_AGG
108108
df = df.resample(freq, label='right').agg(OHLCV_AGG).dropna()
@@ -354,7 +354,7 @@ def _plot_equity_section():
354354
dd_timedelta_label = df['datetime'].iloc[int(round(dd_end))] - df['datetime'].iloc[dd_start]
355355
fig.line([dd_start, dd_end], equity.iloc[dd_start],
356356
line_color='red', line_width=2,
357-
legend_label='Max Dd Dur. ({})'.format(dd_timedelta_label)
357+
legend_label=f'Max Dd Dur. ({dd_timedelta_label})'
358358
.replace(' 00:00:00', '')
359359
.replace('(0 days ', '('))
360360

@@ -424,8 +424,8 @@ def _plot_superimposed_ohlc():
424424
millisecond='S').get(time_resolution))
425425
if not resample_rule:
426426
warnings.warn(
427-
"'Can't superimpose OHLC data with rule '{}' (index datetime resolution: '{}'). "
428-
"Skipping.".format(resample_rule, time_resolution),
427+
f"'Can't superimpose OHLC data with rule '{resample_rule}' (index datetime resolution: '{time_resolution}'). "
428+
"Skipping.",
429429
stacklevel=4)
430430
return
431431

@@ -469,7 +469,7 @@ def _plot_ohlc_trades():
469469
trade_source.add(trades[['EntryPrice', 'ExitPrice']].values.tolist(), 'position_lines_ys')
470470
fig_ohlc.multi_line(xs='position_lines_xs', ys='position_lines_ys',
471471
source=trade_source, line_color=trades_cmap,
472-
legend_label='Trades ({})'.format(len(trades)),
472+
legend_label=f'Trades ({len(trades)})',
473473
line_width=8, line_alpha=1, line_dash='dotted')
474474

475475
def _plot_indicators():
@@ -478,7 +478,7 @@ def _plot_indicators():
478478
def _too_many_dims(value):
479479
assert value.ndim >= 2
480480
if value.ndim > 2:
481-
warnings.warn("Can't plot indicators with >2D ('{}')".format(value.name),
481+
warnings.warn(f"Can't plot indicators with >2D ('{value.name}')",
482482
stacklevel=5)
483483
return True
484484
return False
@@ -517,7 +517,7 @@ def __eq__(self, other):
517517
legend_label = LegendStr(value.name)
518518
for j, arr in enumerate(value, 1):
519519
color = next(colors)
520-
source_name = '{}_{}_{}'.format(legend_label, i, j)
520+
source_name = f'{legend_label}_{i}_{j}'
521521
if arr.dtype == bool:
522522
arr = arr.astype(int)
523523
source.add(arr, source_name)

backtesting/backtesting.py

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ def __str__(self):
6666
map(_as_str, self._params.values())))
6767
if params:
6868
params = '(' + params + ')'
69-
return '{}{}'.format(self.__class__.__name__, params)
69+
return f'{self.__class__.__name__}{params}'
7070

7171
def _check_params(self, params):
7272
for k, v in params.items():
7373
if not hasattr(self, k):
7474
raise AttributeError(
75-
"Strategy '{}' is missing parameter '{}'. Strategy class "
75+
f"Strategy '{self.__class__.__name__}' is missing parameter '{k}'. Strategy class "
7676
"should define parameters as class variables before they "
77-
"can be optimized or run with.".format(self.__class__.__name__, k))
77+
"can be optimized or run with.")
7878
setattr(self, k, v)
7979
return params
8080

@@ -121,15 +121,15 @@ def init():
121121
if name is None:
122122
params = ','.join(filter(None, map(_as_str, chain(args, kwargs.values()))))
123123
func_name = _as_str(func)
124-
name = ('{}({})' if params else '{}').format(func_name, params)
124+
name = (f'{func_name}({params})' if params else f'{func_name}')
125125
else:
126126
name = name.format(*map(_as_str, args),
127127
**dict(zip(kwargs.keys(), map(_as_str, kwargs.values()))))
128128

129129
try:
130130
value = func(*args, **kwargs)
131131
except Exception as e:
132-
raise RuntimeError('Indicator "{}" errored with exception: {}'.format(name, e))
132+
raise RuntimeError(f'Indicator "{name}" errored with exception: {e}')
133133

134134
if isinstance(value, pd.DataFrame):
135135
value = value.values.T
@@ -145,8 +145,7 @@ def init():
145145
if not is_arraylike or not 1 <= value.ndim <= 2 or value.shape[-1] != len(self._data.Close):
146146
raise ValueError(
147147
'Indicators must return (optionally a tuple of) numpy.arrays of same '
148-
'length as `data` (data shape: {}; indicator "{}" shape: {}, returned value: {})'
149-
.format(self._data.Close.shape, name, getattr(value, 'shape', ''), value))
148+
f'length as `data` (data shape: {self._data.Close.shape}; indicator "{name}" shape: {getattr(value, 'shape', '')}, returned value: {value})')
150149

151150
if plot and overlay is None and np.issubdtype(value.dtype, np.number):
152151
x = value / self._data.Close
@@ -293,10 +292,9 @@ def __getattr__(self, item):
293292
removed_attrs = ('entry', 'set_entry', 'is_long', 'is_short',
294293
'sl', 'tp', 'set_sl', 'set_tp')
295294
if item in removed_attrs:
296-
raise AttributeError('Strategy.orders.{} were removed in Backtesting 0.2.0. '
297-
'Use `Order` API instead. See docs.'
298-
.format('/.'.join(removed_attrs)))
299-
raise AttributeError("'tuple' object has no attribute {!r}".format(item))
295+
raise AttributeError(f'Strategy.orders.{"/.".join(removed_attrs)} were removed in Backtesting 0.2.0. '
296+
'Use `Order` API instead. See docs.')
297+
raise AttributeError(f"'tuple' object has no attribute {item!r}")
300298

301299

302300
class Position:
@@ -351,7 +349,7 @@ def close(self, portion: float = 1.):
351349
trade.close(portion)
352350

353351
def __repr__(self):
354-
return '<Position: {} ({} trades)>'.format(self.size, len(self.__broker.trades))
352+
return f'<Position: {self.size} ({len(self.__broker.trades)} trades)>'
355353

356354

357355
class _OutOfMoneyError(Exception):
@@ -518,9 +516,7 @@ def __init__(self, broker: '_Broker', size: int, entry_price: float, entry_bar):
518516
self.__tp_order = None # type: Optional[Order]
519517

520518
def __repr__(self):
521-
return '<Trade size={} time={}-{} price={}-{} pl={:.0f}>'.format(
522-
self.__size, self.__entry_bar, self.__exit_bar or '',
523-
self.__entry_price, self.__exit_price or '', self.pl)
519+
return f'<Trade size={self.__size} time={self.__entry_bar}-{self.__exit_bar or ""} price={self.__entry_price}-{self.__exit_price or ""} pl={self.pl:.0f}>'
524520

525521
def _replace(self, **kwargs):
526522
for k, v in kwargs.items():
@@ -665,9 +661,9 @@ def __set_contingent(self, type, price):
665661
class _Broker:
666662
def __init__(self, *, data, cash, commission, margin,
667663
trade_on_close, hedging, exclusive_orders, index):
668-
assert 0 < cash, "cash shosuld be >0, is {}".format(cash)
669-
assert 0 <= commission < .1, "commission should be between 0-10%, is {}".format(commission)
670-
assert 0 < margin <= 1, "margin should be between 0 and 1, is {}".format(margin)
664+
assert 0 < cash, f"cash shosuld be >0, is {cash}"
665+
assert 0 <= commission < .1, f"commission should be between 0-10%, is {commission}"
666+
assert 0 < margin <= 1, f"margin should be between 0 and 1, is {margin}"
671667
self._data = data # type: _Data
672668
self._cash = cash
673669
self._commission = commission
@@ -683,8 +679,7 @@ def __init__(self, *, data, cash, commission, margin,
683679
self.closed_trades = [] # type: List[Trade]
684680

685681
def __repr__(self):
686-
return '<Broker: {:.0f}{:+.1f} ({} trades)>'.format(
687-
self._cash, self.position.pl, len(self.trades))
682+
return f'<Broker: {self._cash:.0f}{self.position.pl:+.1f} ({len(self.trades)} trades)>'
688683

689684
def new_order(self,
690685
size: float,
@@ -707,12 +702,10 @@ def new_order(self,
707702

708703
if is_long:
709704
if not (sl or -np.inf) <= (limit or stop or self.last_price) <= (tp or np.inf):
710-
raise ValueError("Long orders require: SL ({}) < LIMIT ({}) < TP ({})".format(
711-
sl, limit or stop or self.last_price, tp))
705+
raise ValueError(f"Long orders require: SL ({sl}) < LIMIT ({limit or stop or self.last_price}) < TP ({tp})")
712706
else:
713707
if not (tp or -np.inf) <= (limit or stop or self.last_price) <= (sl or np.inf):
714-
raise ValueError("Short orders require: TP ({}) < LIMIT ({}) < SL ({})".format(
715-
tp, limit or stop or self.last_price, sl))
708+
raise ValueError(f"Short orders require: TP ({tp}) < LIMIT ({limit or stop or self.last_price}) < SL ({sl})")
716709

717710
order = Order(self, size, limit, stop, sl, tp, trade)
718711
# Put the new order in the order queue,
@@ -1237,8 +1230,8 @@ def _tuple(x):
12371230

12381231
for k, v in kwargs.items():
12391232
if len(_tuple(v)) == 0:
1240-
raise ValueError("Optimization variable '{0}' is passed no "
1241-
"optimization values: {0}={1}".format(k, v))
1233+
raise ValueError(f"Optimization variable '{k}' is passed no "
1234+
f"optimization values: {k}={v}")
12421235

12431236
class AttrDict(dict):
12441237
def __getattr__(self, item):
@@ -1253,7 +1246,7 @@ def __getattr__(self, item):
12531246
raise ValueError('No admissible parameter combinations to test')
12541247

12551248
if len(param_combos) > 300:
1256-
warnings.warn('Searching for best of {} configurations.'.format(len(param_combos)),
1249+
warnings.warn(f'Searching for best of {len(param_combos)} configurations.',
12571250
stacklevel=2)
12581251

12591252
heatmap = pd.Series(np.nan,

0 commit comments

Comments
 (0)