У меня есть две серии (bids
и asks
) и список позиций. Все они имеют форму (T, S)
.
В моем примере ниже у меня есть T=5
временных шагов и S=3
символов.
positions
представляет распределение портфеля для каждого символа на каждом временном шаге , Например, если у меня есть 5% актива 1, 10% актива 2 и 85% актива 3 на временном шаге 4, тогда positions[4]
равно [0.05, 0.1, 0.85]
.
При покупке (актив от t
до t+1
увеличивается), следует использовать цены ask
. При продаже следует использовать цены bid
. Это потому, что я предполагаю стратегию, при которой я покупаю / продаю только по рыночным ордерам, поэтому мне нужно каждый раз «пересекать спред».
Как я могу рассчитать свою прибыль, учитывая список позиций во времени, цены спроса и цены предложения?
Для простоты все цены указаны по первому активу (цена которого всегда равна 1), а начальная позиция равна [1, 0, 0]
.
Что бы я хотел это векторизованная реализация функции compute_returns_loop()
(избавление от for
-l oop за временные шаги).
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
T,S=5,3
asks = np.array([[1,1,1,1,1], [3, 3, 3.5, 4, 4], [13, 13, 15, 17, 21]]).T # (T, S)
bids = np.array([[1,1,1,1,1], [1, 1, 2.5, 2, 3], [11, 11, 13, 15, 19]]).T # (T, S)
positions_test_1 = np.array([[1, 0, 0], [1, 0, 0], [1, 0, 0 ], [1, 0, 0 ], [1, 0, 0]]) # (T, S)
positions_test_2 = np.array([[1, 0, 0], [1, 0, 0], [0, 0, 1 ], [0, 0, 1 ], [1, 0, 0]]) # (T, S)
positions_test_3 = np.array([[1, 0, 0], [1, 0, 0], [0.5, 0, 0.5], [0.5, 0, 0.5], [1, 0, 0]]) # (T, S)
positions_test_4 = np.array([[1, 0, 0], [1, 0, 0], [0, 0, 1 ], [1, 0, 0 ], [1, 0, 0]]) # (T, S)
# Quick visualization
plt.plot(asks[:, 2])
plt.plot(bids[:, 2])
# Here absolute means in the currency of the respective asset
# positions are expressed as ratio of the total portfolio allocation
def compute_returns_loop(positions, asks, bids):
mids = (asks + bids) / 2
current_absolute_position = positions[0].astype(np.float)
for t in range(1, asks.shape[0]):
unrealized_worth = (mids[t] * current_absolute_position).sum()
target_absolute_position = positions[t] / mids[t] * unrealized_worth
absolute_transactions = target_absolute_position - current_absolute_position
current_absolute_position[1:] += absolute_transactions[1:]
cost = np.where(absolute_transactions[1:] > 0, asks[t, 1:], bids[t, 1:])
current_absolute_position[0] -= (cost * absolute_transactions[1:]).sum()
return current_absolute_position[0]
def compute_returns_vectorized(positions, asks, bids):
mids = (asks + bids) / 2
# TODO
return None
print(compute_returns_loop(positions_test_1, asks, bids)) # should be 1
print(compute_returns_loop(positions_test_2, asks, bids)) # should be ~1.2
print(compute_returns_loop(positions_test_3, asks, bids)) # should be ~1.1
print(compute_returns_loop(positions_test_4, asks, bids)) # should be 1
# replacing compute_returns_loop with compute_returns_vectorized should give approximately the same results