A 97.6% hit rate on adding to, holding or cutting a position would be the most valuable signal in US equities. How the paper constructs that label goes unexplained. The machinery is buildable. Its reported figures disagree with each other, sometimes even within the same result.
What the allocator actually does
The paper frames its task as optimal capital allocation. Its case for RL starts with mean-variance: normal returns and constant correlations are poor assumptions for non-stationary markets. The proposed allocator observes prices, volume, MACD, volatility and its current weights each day. Dense and LSTM layers form an actor network, whose softmax output produces long-only portfolio weights summing to one. A critic learns the state's value from TD error. The actor updates through an advantage-weighted policy gradient.
The authors name this arrangement Dynamic Actor-Critic, or DAC. Its eight asynchronous workers run parallel market copies and send updates to one global network. They add CPPO, their term for clipped PPO, to keep the probability ratio of the new policy to the old policy within [0.8, 1.2], using an epsilon of 0.2. In the pseudocode, the reward is a Sharpe ratio, μ_t/σ_t. Wealth accrues after the cost function c(a_t, s_t). The proposed source of profit is technical-state-dependent weights; clipping is meant to restrain abrupt policy changes.
Before training, short data gaps receive linear interpolation and longer gaps receive forward-fill. Observations beyond |Z| = 3 are capped or removed. The inputs are then Z-scored and compressed using supervised LDA fitted on the training set. Both datasets come from Kaggle. Massive Yahoo Finance contains 603k daily records, with 9 columns covering the top 500 companies by market cap over five years. Intelligent Finance Assets contains 7,000 records and 32 features spanning equity, bond, commodity, forex and crypto. CPU training lasts 50,000 episodes. The actor learning rate is 0.0003, the critic rate is 0.001, and γ is 0.99.
For the three-class Capital_Action target (Increase, Hold, Decrease), the headline accuracy is 97.6%. The portfolio results give an annualized Sharpe of 1.91 versus a Transformer's 1.72, alongside cumulative return of 1.12 and volatility of 0.14. A 5-fold expanding-window cross-validation produces mean accuracy of 97.4% (SD 0.62).
Four gaps remain in the DAC-CPPO recipe
Table 2 and Algorithm 1 give enough detail to code the networks, clipping and hyperparameters. The details that determine whether the result is real are harder to pin down. We could not find the following in our reading:
- The construction of Capital_Action. Table 1 identifies it as the Yahoo data target, but without a horizon, we cannot say what the 97.6% forecasts.
- The conversion from continuous softmax weights to one of three discrete calls. Every classification metric in Tables 4, 7 and 9 needs that conversion.
- The cost level. The wealth equation includes c(a_t, s_t), yet we found neither a basis-point charge nor turnover. The 1.91 could therefore be gross.
- The way 7,000 multi-asset rows and 603k equity rows become a single environment, or the reason an on-policy method lists a 50,000-transition replay buffer.
Can PPO's 0.2 ratio clip restrain portfolio turnover?
No.
At a given state, π_θ(a|s)/π_θold(a|s) compares two versions of the policy. The bound controls the policy's movement during an optimizer step. Portfolio weights can still jump between day t and t+1. A changing state can send the allocation from one corner of the simplex to another while every ratio stays within [0.8, 1.2]. Turnover and drawdown constraints belong in the action space or reward.
CPPO supposedly introduces "a constrained clipping process, adapted to financial portfolio rebalancing" to bound weight changes during high market variance. As printed, Equation 17 is the standard PPO clipped surrogate. Table 2 specifies a fixed clipping range of 0.2. We found no equation containing the variance-dependent bound.
Table 8 does not separate its contribution either. CPPO alone records Sharpe 0.91 and accuracy 78.5%; preprocessing takes those to 1.10 and 84.6%, and LDA to 1.30 and 90.2%. The full model reaches 1.91 and 97.6%. No Table 8 row shows DAC without clipping. Fig 7 and Fig 8 include both a DAC variant and a PPO variant, but supply an annual Sharpe for neither. The contribution of clipping to 1.91 therefore remains unquantified. The final DAC step by itself reduces volatility from 0.23 to 0.14.
Six contradictions across the split, errors and baselines
The split comes first. Section 2.1 states that "80% of the earliest records are used for training, and the remaining 20% of the most recent records are used for testing". Section 3 gives the opposite account: "80% of the most recent data (the training set) and 20% of the least recent data (the test set)". Later, the text again describes an 80:20 chronological division. Read literally, the second account trains on future observations. A typo could explain it. But this sentence determines whether the exercise qualifies as a backtest.
Table 5 has a separate arithmetic problem. DAC-CPPO's MSE is 0.013 and its RMSE is 0.081. Taking the square root of 0.013 gives 0.114; squaring 0.081 gives 0.0066. Those entries cannot both describe the same predictions. All five baselines from ref [30] have lower RMSE than 0.081, ranging from 0.042 for Transformer to 0.067 for LR. The two entries from ref [28] are higher, at 0.114 and 0.182. Against the [30] entries, the claim of "the lowest" RMSE does not survive.
The authors acknowledge that these values "have been reported in their original units of measurement and thus cannot be compared with one another". They come from other papers using other data. That is the right disclosure. It also strips the adjacent "best" claim of its basis.
The provenance of the baselines changes across tables. Table 4 brings in results from refs [29] and [30], among them FinBERT evaluated on FNSPID news data. In Table 7, every baseline is described as "implemented and trained using" the paper's two datasets. Its figures also differ from Table 4: LSTM records 95.10% versus 93.4%, GB 87.70% versus 91.2%, and BERT-base 67.00% versus 81%. Table 6 credits [28] and [30] for its Sharpe ratios. The accompanying text says the same Sharpe procedure "was consistently applied" to all baselines. The figures cannot be both imported and recomputed.
Return arithmetic creates another conflict. Assume that 1.12 and 0.14 cover Fig 7's 250-trading-day window, approximately a year. Interpreting the return as +112% yields (1.12 - 0.02)/0.14, or about 7.9. Interpreting it as a 1.12x wealth multiple yields (0.12 - 0.02)/0.14, or about 0.71. Neither interpretation produces 1.91. With annual volatility of 0.14, a Sharpe of 1.91 requires annual return near 28.7%.
The confusion matrix is worse. The description gives Increase 4 correct calls and 1 wrong, then Hold 3 correct and 2 wrong. Those described cells contain seven correct calls out of 10, far from the headline 97.6%. Table 9 reports p < 0.001 for a paired t-test without identifying the comparator.
Computational complexity, data quality and high-frequency deployment appear in the authors' limitations. Evaluation does not. The Discussion instead defends the 97.6% as learning and "not just luck of data leakage or an easy classification problem". Its defence relies on the chronological split and class-wise analysis. Section 2.1 also says features were "calculated solely based on historical observations up until the point of prediction". Neither part of the defence holds up: Section 2.1 and Section 3 describe opposite split directions, and the confusion matrix used for class-wise analysis has 10 cases in its described cells.
Our linear substitute lost 93.73% from 2020 to 2024
We backtested the top 500 US stocks by market cap, screening the universe again annually, from 2 January 2020 to 1 July 2024. Daily bars supplied the data. Commissions were $0.004 a share, subject to a $1 minimum. We did not trade the paper's model. Our implementation was a linear scorer penalized for costs, allocating through a softmax with temperature 0.1. It held at most 50 names and rebalanced every 21 sessions.
The result was net Sharpe -0.87, total return -93.73% and maximum drawdown 99.65%. By comparison, the paper reports Sharpe 1.91 and cumulative return 1.12 over an undated test period, with no stated cost. Fig 7 covers 250 trading days. Our result has the opposite sign. Different models and different data produced these figures, so the comparison tells us more about our implementation than theirs.
Some of the gap has an explanation. We omitted LDA, the recurrent networks and PPO, leaving any edge from those components untested. Missing components can explain a flat result. Ours was a wipeout.
Concentration is the strongest single candidate. With temperature 0.1 and a linear scorer fitted at learning rate 0.5, the allocator concentrates capital in few names. Winning trades made up 45.45% of the book. The average loss was about $26,818, against an average gain of $8,748, producing a profit factor of 0.27. Beta to SPY was 0.48, suggesting stock-specific losses rather than market exposure. Our fuller design specified a 2% cap per name.
Another possible contributor appears in the code: max_leverage is 4.0 alongside gross exposure of 1.0. Leverage could have magnified losses, although nothing we can see establishes that it was used. For $1M rebalanced monthly, commissions are probably small relative to the gap. We cannot fully account for a 99.65% drawdown in a nominally long-only large-cap portfolio. A fault in our surrogate remains the likeliest explanation. This run passes no verdict on DAC-CPPO.
What would make the 1.91 Sharpe tradable?
Fig 7 already shows PPO and a benchmark across 250 trading days. Neither receives dates, costs, turnover or a Sharpe. The missing test would run the actual architecture against equal weight over a dated period, include costs, and give a numeric Sharpe for plain PPO using the same networks.
Table 8 supplies the cheapest place to start. Its claim that preprocessing and LDA raise CPPO's Sharpe from 0.91 to 1.30 can be tested without the asynchronous machinery. If plain PPO reaches close to 1.91 on the same inputs, the asynchronous DAC layer contributes nothing. If DAC-CPPO beats equal weight after costs over an identifiable window, with turnover disclosed, the 97.6% becomes beside the point. The strategy would then deserve attention.
Our backtest stops at 2024-07-01, and everything after that date is deliberately left untouched so the same strategy can be checked out of sample later.