If You Knew Tomorrow’s Stock Prices—— Dynamic Programming in Trading
EchoHua0402 · · 个人记录
If You Knew Tomorrow’s Stock Prices — Dynamic Programming in Trading
Introduction
Suppose you knew the exact stock prices for every day of the next few months. Would it then be easy to decide when to buy and sell?
Knowing the future removes uncertainty, but it does not remove the difficulty of decision-making. When every choice changes the possibilities of future choices, finding the optimal strategy becomes an algorithmic problem.
This article explains how dynamic programming finds the most profitable trading strategy without trying every possible sequence of trades.
From Trading Decisions to Mathematical Models
We follow a few trading rules. The account can hold up to
Besides
- the buying price per share is
AP_i ; - the selling price per share is
BP_i ; - we can buy at most
AS_i shares; - we can sell at most
BS_i shares.
We begin with no shares and enough money to cover our purchases. The buying price is at least the selling price on each day. The goal is to maximize the final profit: the total money received from sales minus the total money spent on purchases.
A straightforward idea is to enumerate every possible sequence of buying and selling. However, the number of possible strategies can grow exponentially with time, making this approach impractical even for relatively short periods.
The key observation is that many different trading histories can lead to the same situation.
For example, suppose two strategies reach the same day with the same number of shares, and both have finished their waiting periods. From then on, they have the same trading options. If one has earned less than the other, it cannot produce a better final result by following the same future trades.
This leads to the central idea of dynamic programming:
We do not need to remember every past transaction. We need to keep the information that affects future decisions.
Defining the State
To describe a trading situation, we only need two pieces of information:
- the current day;
- the number of stocks currently held.
Let
Initially, we have no stocks and no profit:
All unreachable states are assigned:
because they cannot contribute to any valid solution.
We can now solve the problem by using state transitions to calculate
State Transition
On each day, there are three possible actions.
1. Do Nothing
If we do not trade today, the number of shares remains unchanged. We first set:
We then check whether buying or selling can give a better result.
2. Buying Shares
If we buy on day
Assume that before buying we owned
Therefore, for every valid
where:
This range ensures that we buy at least one share and no more than today's buying allowance.
3. Selling Shares
Similarly, if we sell
where:
These three cases cover every legal trading schedule. If a transaction happens today, all earlier transactions must finish by day
The final answer is:
There is no benefit to ending with unsold shares when we count only cash income: omitting the purchases of those leftover shares would save money without changing the completed sales.
There are
The table uses
The Bigger Picture
Our DP finds the maximum profit without checking every possible sequence of trades. By reusing the best results for earlier states, it avoids much of the repeated work in brute-force enumeration.
To run it, we need
Here is a C++ implementation you can try in VS Code with a C++ compiler installed. This version allows up to 500 days and 500 shares. You can increase the array size by changing
Enter
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=505;
const ll INF=1e18;
int t,p,w,ap,bp,as,bs;
ll dp[N][N];
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t>>p>>w;
for (int i=0;i<=t;i++)
for (int j=0;j<=p;j++) dp[i][j]=-INF;
dp[0][0]=0;
for (int i=1;i<=t;i++) {
cin>>ap>>bp>>as>>bs;
int pre=max(0,i-w-1);
for (int j=0;j<=p;j++) {
dp[i][j]=dp[i-1][j];
for (int k=max(0,j-as);k<j;k++) {
if (dp[pre][k]==-INF) continue;
dp[i][j]=max(dp[i][j],
dp[pre][k]-1ll*(j-k)*ap);
}
for (int k=j+1;k<=j+min(bs,p-j);k++) {
if (dp[pre][k]==-INF) continue;
dp[i][j]=max(dp[i][j],
dp[pre][k]+1ll*(k-j)*bp);
}
}
}
cout<<dp[t][0]<<'\n';
return 0;
}
The program prints the maximum profit after
Beyond trading, dynamic programming helps businesses plan inventory and reduce ordering and storage costs. It is also used to calculate shortest paths in networks and align DNA sequences to identify similarities. The states and transitions change, but reusing earlier results remains central to each application.