```"""Multipair strategy analyses.

Designed for strategies trading > 5 assets.
"""
import numpy as np
import pandas as pd
from IPython.display import HTML

def _format_value(v: float) -> str:
"""Format US dollar value, no dollar sign."""
return f"{v:,.2f}"

"""Write a single analysis row for a specific pair.

:return:
Dict with raw value

"""

positions = [p for p in portfolio.get_all_positions() if p.pair == pair]

profits = [p.get_total_profit_percent() for p in positions]
best = max(profits)
worst = min(profits)
mean = float(np.mean(profits))
median = float(np.median(profits))
volume = sum([t.get_value() for t in trades])
total_usd_profit = sum([p.get_total_profit_usd() for p in positions])
wins = sum([1 for p in positions if p.get_total_profit_usd() >= 0])
losses = sum([1 for p in positions if p.get_total_profit_usd() >= 0])
take_profits = sum([1 for p in positions if p.is_take_profit()])
stop_losses = sum([1 for p in positions if p.is_stop_loss()])
trailing_stop_losses = sum([1 for p in positions if p.is_trailing_stop_loss()])
total_return = sum(profits)
volatility = np.std(profits)

return {
"Positions": len(positions),
"Total PnL USD": total_usd_profit,
"Best": best,
"Worst": worst,
"Avg": mean,
"Median": median,
"Volume": volume,
"Wins": wins,
"Losses": losses,
"Take profits": take_profits,
"Stop losses": stop_losses,
"Trailing stop losses": trailing_stop_losses,
"Volatility": volatility,
"Total return %": total_return,
}

[docs]def analyse_multipair(state: State) -> pd.DataFrame:
"""Build an analysis table.

Create a table where 1 row = 1 trading pair.

:param state:

:return:
Datframe of the results.

Sorted by the best return.
"""

rows = [analyse_pair_trades(p, state.portfolio) for p in pairs]
df = pd.DataFrame(rows)
return df

[docs]def format_multipair_summary(
df: pd.DataFrame,
sort_column="Total return %",
ascending=False,
format_columns=True
) -> pd.DataFrame:
"""Format the multipair summary table.

Convert raw numbers to preferred human format.

:param df:
Input table.

:param format_columns:
If True, format columns with clickable links. Provided as option since some users may want to export the tables without html markup.

:return:
Dataframe with formatted values for each trading pair.

If there are no trades return empty dataframe.
"""

if len(df) == 0:
return pd.DataFrame()

df = df.sort_values(by=[sort_column], ascending=ascending)

formatters = {
"Positions": str,
"Total PnL USD": _format_value,
"Best": format_percent_2_decimals,
"Worst": format_percent_2_decimals,
"Avg": format_percent_2_decimals,
"Median": format_percent_2_decimals,
"Volume": _format_value,
"Wins": str,
"Losses": str,
"Take profits": str,
"Stop losses": str,
"Trailing stop losses": str,
"Volatility": format_percent_2_decimals,
"Total return %": format_percent_2_decimals,
}

for col, format_func in formatters.items():
df[col] = df[col].apply(format_func)

if format_columns:
("Total PnL USD", None),
("Best", None),
("Worst", None),
("Avg", None),
("Median", None),
("Volume", None),
("Wins", None),
("Losses", None),