| Title: | Estimate Holding Cost Distributions for Chinese Equities |
|---|---|
| Description: | Estimates holding-cost distributions of mainland Chinese A-share equities from daily price, volume, amount and turnover data. Implements the linear turnover-based cost-distribution recurrence of Liu and Wang (2018) <doi:10.1016/j.physa.2017.11.154>, and adds a package-specific exponential-retention alternative and price-allocation choices. Provides optional adjustment factors and initial distributions, offline preparation of 'Tushare' tables, weighted cost summaries and diagnostics for reproducible sensitivity analysis. |
| Authors: | Ruihong Zhao [aut, cre] |
| Maintainer: | Ruihong Zhao <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.1 |
| Built: | 2026-11-10 23:42:18 UTC |
| Source: | https://github.com/cran/asharechips |
Print a brief model summary, extract statistics or weights, or plot estimated cost on the vertical axis against estimated chip share on the horizontal axis.
## S3 method for class 'chip_distribution' print(x, ...) ## S3 method for class 'chip_distribution' summary(object, ...) ## S3 method for class 'chip_distribution' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'chip_distribution' plot(x, ..., col = "#4C78A8", close_col = "#D62728")## S3 method for class 'chip_distribution' print(x, ...) ## S3 method for class 'chip_distribution' summary(object, ...) ## S3 method for class 'chip_distribution' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'chip_distribution' plot(x, ..., col = "#4C78A8", close_col = "#D62728")
x, object
|
A |
... |
For |
row.names, optional
|
Passed to |
col |
Colour for horizontal chip segments. |
close_col |
Colour for the final closing-price reference line. |
summary returns the one-row summary data frame;
as.data.frame returns the distribution data frame.
print and plot return x invisibly.
plot draws on the current graphics device without opening an external
viewer or saving files.
daily <- data.frame( trade_date = c("20260102", "20260105"), high = c(10, 11), low = c(10, 11), close = c(10, 11), vol = c(100, 100), amount = c(100, 110), turnover_rate = c(0, 20) ) chips <- estimate_chip_distribution(daily) print(chips) summary(chips) as.data.frame(chips) plot(chips, main = "Synthetic example", xlab = "Share (%)")daily <- data.frame( trade_date = c("20260102", "20260105"), high = c(10, 11), low = c(10, 11), close = c(10, 11), vol = c(100, 100), amount = c(100, 110), turnover_rate = c(0, 20) ) chips <- estimate_chip_distribution(daily) print(chips) summary(chips) as.data.frame(chips) plot(chips, main = "Synthetic example", xlab = "Share (%)")
Calculate the weighted mean of prices without R's vector recycling. Prices and share counts must correspond in the same order.
chip_mean_cost(price, shares)chip_mean_cost(price, shares)
price |
Non-empty vector of positive, finite prices. Numeric text and factors containing numeric text are also accepted. |
shares |
Equally sized vector of non-negative, finite share counts or weights with a finite positive sum. |
A numeric scalar equal to the sum of prices multiplied by normalized share counts. Prices retain the input monetary units.
chip_mean_cost(c(10, 11, 12), c(50, 20, 30)) # 10.8 chip_mean_cost(c(10, 11, 12), c(0.5, 0.2, 0.3))chip_mean_cost(c(10, 11, 12), c(50, 20, 30)) # 10.8 chip_mean_cost(c(10, 11, 12), c(0.5, 0.2, 0.3))
Estimate the cost distribution of circulating shares using an explicitly specified daily turnover-replacement model. Returns auditable weights, descriptive cost statistics and a per-day diagnostic record.
estimate_chip_distribution( data, date_col = "trade_date", high_col = "high", low_col = "low", close_col = "close", turnover_col = "turnover_rate", volume_col = "vol", amount_col = "amount", adjustment_col = NULL, price_step = 0.01, price_method = c("vwap", "typical", "close", "uniform"), turnover_transform = c("exponential", "linear"), initial_distribution = NULL )estimate_chip_distribution( data, date_col = "trade_date", high_col = "high", low_col = "low", close_col = "close", turnover_col = "turnover_rate", volume_col = "vol", amount_col = "amount", adjustment_col = NULL, price_step = 0.01, price_method = c("vwap", "typical", "close", "uniform"), turnover_transform = c("exponential", "linear"), initial_distribution = NULL )
data |
A non-empty data frame containing one row per observed day and one
stock. A |
date_col |
Date column name. Accepts |
high_col, low_col, close_col
|
Column names for positive finite daily high, low and closing prices in CNY per share. High must be at least low and close must lie in that range. Use unadjusted prices when supplying factors. |
turnover_col |
Column name for non-negative daily turnover in percentage
points: |
volume_col, amount_col
|
Volume and amount column names, required for VWAP. Units are lots of 100 shares and thousand CNY, respectively, as in Tushare daily data. Zero values are permitted together only on rows on which no transaction price is needed. Negative values are rejected. |
adjustment_col |
Optional column name for strictly positive adjustment factors. Historical prices are multiplied by that day's factor divided by the last observed day's factor. Without factors, prices must already share a consistent basis. |
price_step |
Positive price-grid spacing in CNY. Smaller spacing increases resolution and computational work. Grids above one million bins are rejected. The spacing must exceed the numerical resolution of the input prices. |
price_method |
Placement of newly traded weight: |
turnover_transform |
|
initial_distribution |
Optional non-empty data frame with positive
|
Let be the previous grid distribution, the normalized
distribution assigned to newly traded shares and the retention
fraction. The recurrence is
The exponential transformation assumes homogeneous random replacement; the linear alternative assumes a fraction of existing shares changes hands once. Neither transformation identifies actual sellers or individual accounts.
If initial_distribution is NULL, all initial weight is placed
using the first day's price rule. Its turnover is not used as a replacement
step. If an initial distribution is supplied, every row is a replacement step.
history_coverage describes the amount of initial weight replaced by
those steps, not coverage of actual shareholder records.
Point prices are rounded to the nearest grid centre using R's ties-to-even
rounding. Centres are spaced by price_step; the first centre is the
largest non-negative grid multiple not exceeding the minimum input price,
except that a zero centre is replaced by the minimum positive input price.
Uniform allocation uses overlap with cells extending half a step either side
of each centre. A zero-width high-low interval is allocated to one centre.
No arbitrary small-weight threshold is used; only zero numerical weights are
omitted. Very old weights may underflow in long histories.
VWAP values beyond the high-low range by more than
1e-6 * max(1, high) in original price units are rejected. Smaller
rounding discrepancies are clamped to the range and flagged. The optional
float_share column must be positive; a consecutive relative change
above 1e-6 produces a warning and a diagnostic flag. Issuances, unlocks,
repurchases, fees and taxes are not modelled. Dividend factors provide a
comparable price basis rather than literal historical cash acquisition costs.
Runtime is approximately proportional to the product of the number of days and grid bins. Memory usage is proportional to bins plus input rows.
A chip_distribution object, a list with four components:
Data frame with positive grid price, normalized
weight (sum one, subject to numerical precision), and
percent = 100 * weight.
One-row data frame, with these groups of fields:
Stock identifier: ts_code.
Date interval: start_date and end_date.
Input count: observations. Final price: last_close.
Weighted mean: average_cost. Weighted median: median_cost.
Peak cost: peak_price. Peak share: peak_percent.
Tied peaks use the lowest price.
Profitable share: profit_ratio and profit_percent;
only costs strictly below the last close are included.
Equal-price share: breakeven_ratio. Higher-cost share:
loss_ratio. Equality allows only numerical rounding error.
The profit, break-even and loss ratios sum to one.
Central interval: cost_low_90 and cost_high_90, the
discrete 5th and 95th weighted quantiles.
Range width: concentration_90, the interval's width divided
by the sum of its endpoints. Smaller values mean narrower cost ranges,
not higher ownership concentration.
Turnover sum: cumulative_turnover_percent, over applied rows.
Surviving prior: initialization_weight, the product of
retention fractions over applied update rows.
Replaced prior: history_coverage, one minus surviving prior.
One row per sorted date with the following fields:
Date: trade_date. Turnover: turnover_rate.
Proposed replacement: replacement_fraction.
Used replacement: applied_replacement_fraction; zero for
an initialized first row.
Old-weight retention: retention.
Final-basis price: transaction_price.
Original-basis price: raw_transaction_price.
Factor normalization: adjustment_ratio.
Minor VWAP corrections: vwap_rounding_adjusted.
Initialization flag: initialized_here.
Share-count change flag: capital_changed.
vwap_outside_range is retained for backwards
compatibility and is always false because material violations are errors.
Uniform allocation's transaction price is a representative typical price,
not the allocation itself.
Column mappings, grid spacing and origin, price and turnover
methods, initialization rule and price_basis = "last_trading_day".
The estimates depend on modelling assumptions, observed history and grid spacing. They do not establish investor identity or future returns.
Liu, H. and Wang, L. (2018). “The price momentum of stock in distribution.” Physica A: Statistical Mechanics and its Applications, 492, 2336–2344. doi:10.1016/j.physa.2017.11.154.
Tushare daily prices and units: https://tushare.pro/document/2?doc_id=27. Turnover definitions: https://tushare.pro/document/2?doc_id=32. Adjustment factors: https://tushare.pro/document/2?doc_id=28.
prepare_tushare_data, chip_mean_cost,
plot.chip_distribution
# Entirely synthetic data; no network access or API token is required. daily <- data.frame( trade_date = c("20260106", "20260102", "20260105"), high = c(12, 10, 11), low = c(12, 10, 11), close = c(12, 10, 11), vol = c(100, 100, 100), amount = c(120, 100, 110), turnover_rate = c(30, 0, 20) ) chips <- estimate_chip_distribution(daily) summary(chips) as.data.frame(chips) initial <- data.frame(price = c(8, 12), weight = c(0.5, 0.5)) estimate_chip_distribution(daily, initial_distribution = initial)# Entirely synthetic data; no network access or API token is required. daily <- data.frame( trade_date = c("20260106", "20260102", "20260105"), high = c(12, 10, 11), low = c(12, 10, 11), close = c(12, 10, 11), vol = c(100, 100, 100), amount = c(120, 100, 110), turnover_rate = c(30, 0, 20) ) chips <- estimate_chip_distribution(daily) summary(chips) as.data.frame(chips) initial <- data.frame(price = c(8, 12), weight = c(0.5, 0.5)) estimate_chip_distribution(daily, initial_distribution = initial)