@gabriel3615/ta_analysis
Version:
stock ta analysis
207 lines (206 loc) • 8.63 kB
JavaScript
/**
* 模拟股票滚仓策略,计算降低成本所需的循环次数
* 该策略通过在价格下跌时买入,上涨时卖出,逐步降低持仓成本
* @param initState 初始参数设置
* @returns 滚仓策略模拟结果
*/
function simulateStockTrading(initState) {
const { initialShares, initialPrice, currentPrice, feePerTrade, downPercent, upPercent, tradingRatio, maxCycles, volatility, } = initState;
// 初始状态计算
let totalInvestment = initialShares * initialPrice;
const tradingPosition = Math.floor(initialShares * tradingRatio);
const fixedPosition = initialShares - tradingPosition;
// 当前状态
let currentShares = initialShares;
let avgCost = totalInvestment / currentShares;
let totalFees = 0;
let cashBalance = 0;
// 结果数据存储
let cycles = 0;
let price = currentPrice;
const tradeHistory = [];
// 输出初始情况
const initialState = {
initialShares,
initialPrice,
currentPrice,
totalInvestment,
currentMarketValue: currentShares * currentPrice,
avgCost,
tradingPosition,
fixedPosition,
feePerTrade,
};
// 模拟滚仓过程
while (avgCost > currentPrice && cycles < maxCycles) {
cycles++;
// 下跌买入
const buyPrice = price * (1 - downPercent);
const buyValue = tradingPosition * buyPrice;
const buyFee = feePerTrade;
cashBalance -= buyValue + buyFee;
totalFees += buyFee;
// 计算新的持股和成本
currentShares += tradingPosition;
totalInvestment += buyValue + buyFee;
avgCost = totalInvestment / currentShares;
// 记录买入交易
const buyTrade = {
type: 'buy',
cycle: cycles,
price: buyPrice,
shares: tradingPosition,
value: buyValue,
fee: buyFee,
newShares: currentShares,
newAvgCost: avgCost,
};
// 上涨卖出
const sellPrice = buyPrice * (1 + upPercent);
const sellValue = tradingPosition * sellPrice;
const sellFee = feePerTrade;
cashBalance += sellValue - sellFee;
totalFees += sellFee;
// 计算新的持股和成本
currentShares -= tradingPosition;
// 此处修正:卖出的股票按平均成本计算对总投资的影响
totalInvestment -= tradingPosition * avgCost;
avgCost = totalInvestment / currentShares;
// 计算单次循环利润
const cycleProfitLoss = sellValue - buyValue - buyFee - sellFee;
// 记录卖出交易
const sellTrade = {
type: 'sell',
cycle: cycles,
price: sellPrice,
shares: tradingPosition,
value: sellValue,
fee: sellFee,
newShares: currentShares,
newAvgCost: avgCost,
cycleProfitLoss,
};
// 保存交易记录
tradeHistory.push(buyTrade, sellTrade);
const lastPrice = price;
// 更新价格基准,假设长期趋势稳定在初始的当前价格附近
price = lastPrice * (1 + (Math.random() * 2 - 1) * volatility);
}
// 计算回本所需涨幅
const breakEvenGrowth = (avgCost / currentPrice - 1) * 100;
// 返回分析结果
return {
initialState,
finalState: {
cycles,
finalShares: currentShares,
finalAvgCost: avgCost,
costReductionPercent: (1 - avgCost / initialPrice) * 100,
totalFees,
cashBalance,
breakEvenPrice: avgCost,
breakEvenGrowth,
},
tradeHistory,
parameterSettings: {
downPercent,
upPercent,
tradingRatio,
feePerTrade,
},
};
}
/**
* 运行滚仓模拟并格式化输出结果
* @param initState 初始参数
* @param printDetails 是否打印详细交易历史
* @returns 格式化的输出结果
*/
function runAvgDownSimulation(initState, printDetails) {
// 运行模拟
const result = simulateStockTrading(initState);
let output = '';
// 输出结果摘要
output += '初始情况:\n';
output += `持股数量: ${result.initialState.initialShares}股\n`;
output += `初始买入价: ${result.initialState.initialPrice}元\n`;
output += `当前股价: ${result.initialState.currentPrice}元\n`;
output += `总投资: ${result.initialState.totalInvestment}元\n`;
output += `当前市值: ${result.initialState.currentMarketValue}元\n`;
output += `初始平均成本: ${result.initialState.avgCost}元\n`;
output += `滚仓交易股数: ${result.initialState.tradingPosition}股\n`;
output += `固定持有股数: ${result.initialState.fixedPosition}股\n`;
output += `每次交易手续费: ${result.initialState.feePerTrade}元\n`;
output += '-------------------------\n';
output += `总结:\n`;
output += `完成循环次数: ${result.finalState.cycles}\n`;
output += `最终平均成本: ${result.finalState.finalAvgCost.toFixed(2)}元\n`;
output += `成本降低百分比: ${result.finalState.costReductionPercent.toFixed(2)}%\n`;
output += `累计手续费: ${result.finalState.totalFees}元\n`;
output += `累计现金收益: ${result.finalState.cashBalance.toFixed(2)}元\n`;
output += `要回到初始投资,股价需要从当前的${initState.currentPrice}元上涨到${result.finalState.breakEvenPrice.toFixed(2)}元,涨幅${result.finalState.breakEvenGrowth.toFixed(2)}%\n`;
// 打印详细交易历史可选
if (printDetails) {
// 设置为true以显示详细交易历史
output += '\n交易历史:\n';
result.tradeHistory.forEach(trade => {
if (trade.type === 'buy') {
output += `第${trade.cycle}次买入: 价格${trade.price.toFixed(2)}元,${trade.shares}股,费用${trade.fee}元,新平均成本${trade.newAvgCost.toFixed(2)}元\n`;
}
else {
output += `第${trade.cycle}次卖出: 价格${trade.price.toFixed(2)}元,${trade.shares}股,费用${trade.fee}元,利润${trade.cycleProfitLoss.toFixed(2)}元,新平均成本${trade.newAvgCost.toFixed(2)}元\n`;
}
});
}
return output;
}
/**
* 比较不同参数设置对滚仓策略效果的影响
* @param initState 基础参数设置
* @returns 不同参数比较的结果报告
*/
function compareAvgDownParameters(initState) {
let output = '';
output += '\n参数比较分析:\n';
// 测试不同的下跌买入/上涨卖出百分比
const scenarios = [
{ name: '保守策略', down: 0.1, up: 0.1 },
{ name: '标准策略', down: 0.2, up: 0.2 },
{ name: '激进策略', down: 0.3, up: 0.3 },
{ name: '非对称策略1', down: 0.15, up: 0.25 },
{ name: '非对称策略2', down: 0.25, up: 0.15 },
];
scenarios.forEach(scenario => {
// 创建参数副本并应用场景特定参数
const scenarioState = {
...initState,
downPercent: scenario.down,
upPercent: scenario.up,
};
const result = simulateStockTrading(scenarioState);
output += `${scenario.name} (下跌${scenario.down * 100}%买入,上涨${scenario.up * 100}%卖出):\n`;
output += ` 循环次数: ${result.finalState.cycles}\n`;
output += ` 最终成本: ${result.finalState.finalAvgCost.toFixed(2)}元\n`;
output += ` 回本涨幅: ${result.finalState.breakEvenGrowth.toFixed(2)}%\n`;
output += ` 现金收益: ${result.finalState.cashBalance.toFixed(2)}元\n`;
});
return output;
}
const initState = {
initialShares: 100, // 初始持有100股
initialPrice: 30, // 初始买入价格30元
currentPrice: 15, // 当前市场价格15元
feePerTrade: 3, // 每次交易手续费3元
downPercent: 0.1, // 价格下跌10%触发买入
upPercent: 0.1, // 价格上涨10%触发卖出
tradingRatio: 1 / 3, // 使用1/3的股票进行滚仓交易
maxCycles: 100, // 最多允许100个循环
volatility: 0.1, // 价格波动率10%
};
// 运行模拟并获取结果
// const result1 = runAvgDownSimulation(initState, true);
// console.log(result1);
// 取消注释下面一行以运行不同参数的比较
// const result2 = compareAvgDownParameters(initState);
// console.log(result2);
export { runAvgDownSimulation, compareAvgDownParameters, simulateStockTrading, };