Anonymous
Polars: расширенный алгоритм перекрестной торговли
Сообщение
Anonymous » 16 сен 2024, 23:31
У меня есть полярный фрейм данных, содержащий доходность акций, а также перекрестные ранги в аккуратном/длинном pl.DataFrame.
Код: Выделить всё
prices = pl.DataFrame(
{
"symbol": [
*["symbol1"] * 6, *["symbol2"] * 5, *["symbol3"] * 5, *["symbol4"] * 6,
],
"date": [
"2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06",
"2023-12-30", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06",
"2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05",
"2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06",
],
"price": [
100, 105, 110, 115, 120, 125,
200, 210, 220, 230, 240,
3000, 3100, 3200, 3300, 3400,
1000, 1050, 1080, 1090, 1300, 1350,
],
}
)
shape: (22, 3)
┌─────────┬────────────┬───────┐
│ symbol ┆ date ┆ price │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 │
╞═════════╪════════════╪═══════╡
│ symbol1 ┆ 2023-12-30 ┆ 100 │
│ symbol1 ┆ 2023-12-31 ┆ 105 │
│ symbol1 ┆ 2024-01-03 ┆ 110 │
│ symbol1 ┆ 2024-01-04 ┆ 115 │
│ symbol1 ┆ 2024-01-05 ┆ 120 │
│ symbol1 ┆ 2024-01-06 ┆ 125 │
│ symbol2 ┆ 2023-12-30 ┆ 200 │
│ symbol2 ┆ 2024-01-03 ┆ 210 │
│ symbol2 ┆ 2024-01-04 ┆ 220 │
│ symbol2 ┆ 2024-01-05 ┆ 230 │
│ symbol2 ┆ 2024-01-06 ┆ 240 │
│ symbol3 ┆ 2023-12-30 ┆ 3000 │
│ symbol3 ┆ 2023-12-31 ┆ 3100 │
│ symbol3 ┆ 2024-01-03 ┆ 3200 │
│ symbol3 ┆ 2024-01-04 ┆ 3300 │
│ symbol3 ┆ 2024-01-05 ┆ 3400 │
│ symbol4 ┆ 2023-12-30 ┆ 1000 │
│ symbol4 ┆ 2023-12-31 ┆ 1050 │
│ symbol4 ┆ 2024-01-03 ┆ 1080 │
│ symbol4 ┆ 2024-01-04 ┆ 1090 │
│ symbol4 ┆ 2024-01-05 ┆ 1300 │
│ symbol4 ┆ 2024-01-06 ┆ 1350 │
└─────────┴────────────┴───────┘
Простой алгоритм перекрестной торговли выглядит примерно так:
Определите наиболее эффективный символ в период (здесь: рейтинг возвращается за два периода по всем символам на каждую дату).
Вставьте (купите) символ и поместите его в свое портфолио.
< li>Повторите процесс для каждого периода (даты).
Код: Выделить всё
returns_ranked = (
prices.with_columns(pl.col("price").pct_change(2).over("symbol").alias("return"))
.with_columns(
rank=pl.col("return")
.rank(descending=True, method="random")
.over("date")
.cast(pl.UInt8)
)
.with_columns(in_portfolio=pl.when(pl.col("rank") == 1).then(True).otherwise(False))
)
shape: (22, 6)
┌─────────┬────────────┬───────┬──────────┬──────┬──────────────┐
│ symbol ┆ date ┆ price ┆ return ┆ rank ┆ in_portfolio │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 ┆ f64 ┆ u8 ┆ bool │
╞═════════╪════════════╪═══════╪══════════╪══════╪══════════════╡
│ symbol1 ┆ 2023-12-30 ┆ 100 ┆ null ┆ null ┆ false │
│ symbol1 ┆ 2023-12-31 ┆ 105 ┆ null ┆ null ┆ false │
│ symbol1 ┆ 2024-01-03 ┆ 110 ┆ 0.1 ┆ 1 ┆ true │
│ symbol1 ┆ 2024-01-04 ┆ 115 ┆ 0.095238 ┆ 2 ┆ false │
│ symbol1 ┆ 2024-01-05 ┆ 120 ┆ 0.090909 ┆ 3 ┆ false │
│ symbol1 ┆ 2024-01-06 ┆ 125 ┆ 0.086957 ┆ 3 ┆ false │
│ symbol2 ┆ 2023-12-30 ┆ 200 ┆ null ┆ null ┆ false │
│ symbol2 ┆ 2024-01-03 ┆ 210 ┆ null ┆ null ┆ false │
│ symbol2 ┆ 2024-01-04 ┆ 220 ┆ 0.1 ┆ 1 ┆ true │
│ symbol2 ┆ 2024-01-05 ┆ 230 ┆ 0.095238 ┆ 2 ┆ false │
│ symbol2 ┆ 2024-01-06 ┆ 240 ┆ 0.090909 ┆ 2 ┆ false │
│ symbol3 ┆ 2023-12-30 ┆ 3000 ┆ null ┆ null ┆ false │
│ symbol3 ┆ 2023-12-31 ┆ 3100 ┆ null ┆ null ┆ false │
│ symbol3 ┆ 2024-01-03 ┆ 3200 ┆ 0.066667 ┆ 3 ┆ false │
│ symbol3 ┆ 2024-01-04 ┆ 3300 ┆ 0.064516 ┆ 3 ┆ false │
│ symbol3 ┆ 2024-01-05 ┆ 3400 ┆ 0.0625 ┆ 4 ┆ false │
│ symbol4 ┆ 2023-12-30 ┆ 1000 ┆ null ┆ null ┆ false │
│ symbol4 ┆ 2023-12-31 ┆ 1050 ┆ null ┆ null ┆ false │
│ symbol4 ┆ 2024-01-03 ┆ 1080 ┆ 0.08 ┆ 2 ┆ false │
│ symbol4 ┆ 2024-01-04 ┆ 1090 ┆ 0.038095 ┆ 4 ┆ false │
│ symbol4 ┆ 2024-01-05 ┆ 1300 ┆ 0.203704 ┆ 1 ┆ true │
│ symbol4 ┆ 2024-01-06 ┆ 1350 ┆ 0.238532 ┆ 1 ┆ true │
└─────────┴────────────┴───────┴──────────┴──────┴──────────────┘
Столбец in_portfolio определяет наиболее эффективный инструмент за каждый период. Пока все хорошо.
Теперь давайте усовершенствуем этот алгоритм. Вместо того, чтобы просто покупать наиболее эффективный символ, новый алгоритм выглядит следующим образом:
Определите наиболее эффективный символ за период (здесь: рейтинг возвращается за два периодов по всем символам на каждую дату).
Вставьте (купите) символ и поместите его в свой портфель.
В следующем периоде вы продавайте символ только в том случае, если его рейтинг меньше 2. Только тогда символ с самым высоким рейтингом в этот период заменит предыдущий символ.
Проблема здесь заключается в том, что этот новый алгоритм всегда зависит от предыдущего периода. Нам нужно знать, был ли символ в портфеле в предыдущем периоде, чтобы проверить, не является ли его текущий ранг меньше 2. То есть мы вводим зависимость от пути.
I ищу векторизованное решение. Потенциально я работаю с огромным набором данных.
Подробнее здесь:
https://stackoverflow.com/questions/789 ... -algorithm
1726518679
Anonymous
У меня есть полярный фрейм данных, содержащий доходность акций, а также перекрестные ранги в аккуратном/длинном pl.DataFrame. [code]prices = pl.DataFrame( { "symbol": [ *["symbol1"] * 6, *["symbol2"] * 5, *["symbol3"] * 5, *["symbol4"] * 6, ], "date": [ "2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06", "2023-12-30", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06", "2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06", ], "price": [ 100, 105, 110, 115, 120, 125, 200, 210, 220, 230, 240, 3000, 3100, 3200, 3300, 3400, 1000, 1050, 1080, 1090, 1300, 1350, ], } ) shape: (22, 3) ┌─────────┬────────────┬───────┐ │ symbol ┆ date ┆ price │ │ --- ┆ --- ┆ --- │ │ str ┆ str ┆ i64 │ ╞═════════╪════════════╪═══════╡ │ symbol1 ┆ 2023-12-30 ┆ 100 │ │ symbol1 ┆ 2023-12-31 ┆ 105 │ │ symbol1 ┆ 2024-01-03 ┆ 110 │ │ symbol1 ┆ 2024-01-04 ┆ 115 │ │ symbol1 ┆ 2024-01-05 ┆ 120 │ │ symbol1 ┆ 2024-01-06 ┆ 125 │ │ symbol2 ┆ 2023-12-30 ┆ 200 │ │ symbol2 ┆ 2024-01-03 ┆ 210 │ │ symbol2 ┆ 2024-01-04 ┆ 220 │ │ symbol2 ┆ 2024-01-05 ┆ 230 │ │ symbol2 ┆ 2024-01-06 ┆ 240 │ │ symbol3 ┆ 2023-12-30 ┆ 3000 │ │ symbol3 ┆ 2023-12-31 ┆ 3100 │ │ symbol3 ┆ 2024-01-03 ┆ 3200 │ │ symbol3 ┆ 2024-01-04 ┆ 3300 │ │ symbol3 ┆ 2024-01-05 ┆ 3400 │ │ symbol4 ┆ 2023-12-30 ┆ 1000 │ │ symbol4 ┆ 2023-12-31 ┆ 1050 │ │ symbol4 ┆ 2024-01-03 ┆ 1080 │ │ symbol4 ┆ 2024-01-04 ┆ 1090 │ │ symbol4 ┆ 2024-01-05 ┆ 1300 │ │ symbol4 ┆ 2024-01-06 ┆ 1350 │ └─────────┴────────────┴───────┘ [/code] Простой алгоритм перекрестной торговли выглядит примерно так: [list] [*]Определите наиболее эффективный символ в период (здесь: рейтинг возвращается за два периода по всем символам на каждую дату). [*]Вставьте (купите) символ и поместите его в свое портфолио. < li>Повторите процесс для каждого периода (даты). [/list] [code] returns_ranked = ( prices.with_columns(pl.col("price").pct_change(2).over("symbol").alias("return")) .with_columns( rank=pl.col("return") .rank(descending=True, method="random") .over("date") .cast(pl.UInt8) ) .with_columns(in_portfolio=pl.when(pl.col("rank") == 1).then(True).otherwise(False)) ) shape: (22, 6) ┌─────────┬────────────┬───────┬──────────┬──────┬──────────────┐ │ symbol ┆ date ┆ price ┆ return ┆ rank ┆ in_portfolio │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ str ┆ i64 ┆ f64 ┆ u8 ┆ bool │ ╞═════════╪════════════╪═══════╪══════════╪══════╪══════════════╡ │ symbol1 ┆ 2023-12-30 ┆ 100 ┆ null ┆ null ┆ false │ │ symbol1 ┆ 2023-12-31 ┆ 105 ┆ null ┆ null ┆ false │ │ symbol1 ┆ 2024-01-03 ┆ 110 ┆ 0.1 ┆ 1 ┆ true │ │ symbol1 ┆ 2024-01-04 ┆ 115 ┆ 0.095238 ┆ 2 ┆ false │ │ symbol1 ┆ 2024-01-05 ┆ 120 ┆ 0.090909 ┆ 3 ┆ false │ │ symbol1 ┆ 2024-01-06 ┆ 125 ┆ 0.086957 ┆ 3 ┆ false │ │ symbol2 ┆ 2023-12-30 ┆ 200 ┆ null ┆ null ┆ false │ │ symbol2 ┆ 2024-01-03 ┆ 210 ┆ null ┆ null ┆ false │ │ symbol2 ┆ 2024-01-04 ┆ 220 ┆ 0.1 ┆ 1 ┆ true │ │ symbol2 ┆ 2024-01-05 ┆ 230 ┆ 0.095238 ┆ 2 ┆ false │ │ symbol2 ┆ 2024-01-06 ┆ 240 ┆ 0.090909 ┆ 2 ┆ false │ │ symbol3 ┆ 2023-12-30 ┆ 3000 ┆ null ┆ null ┆ false │ │ symbol3 ┆ 2023-12-31 ┆ 3100 ┆ null ┆ null ┆ false │ │ symbol3 ┆ 2024-01-03 ┆ 3200 ┆ 0.066667 ┆ 3 ┆ false │ │ symbol3 ┆ 2024-01-04 ┆ 3300 ┆ 0.064516 ┆ 3 ┆ false │ │ symbol3 ┆ 2024-01-05 ┆ 3400 ┆ 0.0625 ┆ 4 ┆ false │ │ symbol4 ┆ 2023-12-30 ┆ 1000 ┆ null ┆ null ┆ false │ │ symbol4 ┆ 2023-12-31 ┆ 1050 ┆ null ┆ null ┆ false │ │ symbol4 ┆ 2024-01-03 ┆ 1080 ┆ 0.08 ┆ 2 ┆ false │ │ symbol4 ┆ 2024-01-04 ┆ 1090 ┆ 0.038095 ┆ 4 ┆ false │ │ symbol4 ┆ 2024-01-05 ┆ 1300 ┆ 0.203704 ┆ 1 ┆ true │ │ symbol4 ┆ 2024-01-06 ┆ 1350 ┆ 0.238532 ┆ 1 ┆ true │ └─────────┴────────────┴───────┴──────────┴──────┴──────────────┘ [/code] Столбец in_portfolio определяет наиболее эффективный инструмент за каждый период. Пока все хорошо. Теперь давайте усовершенствуем этот алгоритм. Вместо того, чтобы просто покупать наиболее эффективный символ, новый алгоритм выглядит следующим образом: [list] [*]Определите наиболее эффективный символ за период (здесь: рейтинг возвращается за два периодов по всем символам на каждую дату). [*]Вставьте (купите) символ и поместите его в свой портфель. [*]В следующем периоде вы продавайте символ только в том случае, если его рейтинг меньше 2. Только тогда символ с самым высоким рейтингом в этот период заменит предыдущий символ. [/list] Проблема здесь заключается в том, что этот новый алгоритм всегда зависит от предыдущего периода. Нам нужно знать, был ли символ в портфеле в предыдущем периоде, чтобы проверить, не является ли его текущий ранг меньше 2. То есть мы вводим зависимость от пути. I ищу векторизованное решение. Потенциально я работаю с огромным набором данных. Подробнее здесь: [url]https://stackoverflow.com/questions/78991594/polars-advanced-cross-sectional-trading-algorithm[/url]