Как увеличить доход - Python

У меня есть большой df, состоящий из почасовых цен на акции. Я надеялся найти оптимальную цену покупки и цены продажи, чтобы максимизировать прибыль (доход - затраты). Я понятия не имею, какими будут максимальные цены покупки / продажи, поэтому мое первоначальное предположение - дикий удар в темноте.

Я попытался использовать Scipy «минимизировать» и «тазовый прыжок». Когда я запускаю сценарий, мне кажется, что я застреваю в местных колодцах, и результаты почти не отличаются от моих первоначальных предположений.

Любые идеи о том, как я могу это решить? есть ли лучший способ написать код или лучший метод для использования.

Пример кода ниже

import pandas as pd
import numpy as np
import scipy.optimize as optimize

df = pd.DataFrame({
    'Time': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'Price': [44, 100, 40, 110, 77, 109, 65, 93, 89, 49]})

# Create Empty Columns
df[['Qty', 'Buy', 'Sell', 'Cost', 'Rev']] = pd.DataFrame([[0.00, 0.00, 0.00, 0.00, 0.00]], index=df.index)


# Create Predicate to add fields
class Predicate:
    def __init__(self):
        self.prev_time = -1
        self.prev_qty = 0
        self.prev_buy = 0
        self.prev_sell = 0
        self.Qty = 0
        self.Buy = 0
        self.Sell = 0
        self.Cost = 0
        self.Rev = 0

    def __call__(self, x):
        if x.Time == self.prev_time:
            x.Qty = self.prev_qty
            x.Buy = self.prev_buy
            x.Sell = self.prev_sell
            x.Cost = x.Buy * x.Price
            x.Rev = x.Sell * x.Price
        else:
            x.Qty = self.prev_qty + self.prev_buy - self.prev_sell
            x.Buy = np.where(x.Price < buy_price, min(30 - x.Qty, 10), 0)
            x.Sell = np.where(x.Price > sell_price, min(x.Qty, 10), 0)
            x.Cost = x.Buy * x.Price
            x.Rev = x.Sell * x.Price
            self.prev_buy = x.Buy
            self.prev_qty = x.Qty
            self.prev_sell = x.Sell
            self.prev_time = x.Time
        return x


# Define function to minimize
def max_rev(params):
    global buy_price
    global sell_price
    buy_price, sell_price = params
    df2 = df.apply(Predicate(), axis=1)
    return -1 * (df2['Rev'].sum() - df2['Cost'].sum())


# Run optimization
initial_guess = [40, 90]
result = optimize.minimize(fun=max_rev, x0=initial_guess, method='BFGS')
# result = optimize.basinhopping(func=max_rev, x0=initial_guess, niter=1000, stepsize=10)
print(result.x)

# Run the final results
result.x = buy_price, sell_price
df = df.apply(Predicate(), axis=1)
print(df)
print(df['Rev'].sum() - df['Cost'].sum())

person Bobby Heyer    schedule 31.10.2019    source источник
comment
Я думаю, что это может быть не проблема минимизации или прыжков по бассейну, а скорее классическая проблема динамического программирования. Я сам немного не уверен в методах, но scipy, вероятно, не требуется. Если от вас требуется использование scipy, обязательно сообщите об этом.   -  person DarthCadeus    schedule 31.10.2019


Ответы (1)


Вы не вдавались в подробности, но я предполагаю, что вы рассматриваете проблему максимизации дохода с помощью «идеального предвидения», то есть с самого начала вы знаете, как цена будет развиваться в будущем.

Эту проблему довольно легко решить, но, насколько я могу судить на данный момент, ваша проблема не ограничена - вы можете получить сколь угодно большой доход, купив бесконечное количество единиц по низкой цене и продав их по высокой.

Вам нужно добавить ограничение, что вы можете начать только с конечной суммой наличных и что вы можете продавать только те акции, которые принадлежат вам (это не совсем так, можно «продать в шорт» там, где вы продаете вещи сейчас. на ожидании, что его стоимость упадет (когда вам придется покупать его позже).

Игнорируя махинации с короткими продажами, вы можете сформулировать задачу оптимизации в виде линейной программы следующим образом:

import pandas as pd
import numpy as np
from pulp import *

# Problem Data
df = pd.DataFrame({
    'Time': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'Price': [44, 100, 40, 110, 77, 109, 65, 93, 89, 49]})

times = list(df.Time)
times_plus_1 = times + [times[-1] + 1]

# Instantiate maximisation problem
prob = LpProblem("numpy_constraints", LpMaximize)

# Create the problem vairables
# Cash in bank and stock-level at start of each interval
Cash = pulp.LpVariable.dicts("Cash", times_plus_1, cat='Continuous', lowBound=0)
Stock = pulp.LpVariable.dicts("Stock", times_plus_1, cat='Continuous', lowBound=0)

# Amount bought during interval
Buy = pulp.LpVariable.dicts("Buy", times, cat='Continuous')

# Add Objective to problem - cash at end of period modelled
prob += Cash[times_plus_1[-1]]

# Add constraints
# Start with a single dollar in the bank & no stock
prob += Cash[times[0]] == 1.0
prob += Stock[times[0]] == 0.0

# Cash & stock update rules
for t in times:
    prob += Cash[t+1] == Cash[t] - Buy[t]*df.Price[t]
    prob += Stock[t+1] == Stock[t] + Buy[t]

# Solve
prob.solve()

# Check when we bought when:
Buy_soln = np.array([Buy[t].varValue for t in times])
print("Buy_soln:")
print(Buy_soln)

Stock_soln = np.array([Stock[t].varValue for t in times_plus_1])
print("Stock_soln:")
print(Stock_soln)

Cash_soln = np.array([Cash[t].varValue for t in times_plus_1])
print("Cash_soln:")
print(Cash_soln)

В результате получается следующее:

Buy_soln:
[ 0.02272727 -0.02272727  0.05681818 -0.05681818  0.08116883 -0.08116883
  0.13611389 -0.13611389  0.          0.        ]
Stock_soln:
[0.         0.02272727 0.         0.05681818 0.         0.08116883
 0.         0.13611389 0.         0.         0.        ]
Cash_soln:
[ 1.         0.         2.2727273  0.         6.25       0.
  8.8474026  0.        12.658591  12.658591  12.658591 ]

Не особенно интересно - как и ожидалось, используйте все доступные наличные деньги, чтобы использовать любое повышение цены акций (покупать дешево, продавать дорого).

person kabdulla    schedule 31.10.2019
comment
Большое спасибо за ваш ответ. Это работает как шарм. У меня был только один быстрый вопрос. В исходной версии я как бы наложил ограничения. x.Buy & x.Sell были ограничены покупкой / продажей 10 акций в любое время, а x.Qty было ограничено максимум 30. Есть ли способ изменить ограничения в той версии, которую вы применили к ним? - person Bobby Heyer; 01.11.2019
comment
Привет, Бобби. Да, это было бы легко сделать. Просто добавьте нижнюю и верхнюю границы к переменным Stock и Buy. - person kabdulla; 01.11.2019