@gabriel3615/ta_analysis
Version:
stock ta analysis
250 lines (249 loc) • 9.71 kB
JavaScript
import { getStockDataForTimeframe } from '../util/util.js';
/**
* 模拟特定波动率下的股价路径
* @returns 每日股价数组
* @param symbol
*/
async function getPrices(symbol) {
const today = new Date();
console.log('正在获取数据...');
const startDate = new Date();
startDate.setDate(today.getDate() - 360); // 获取一年的数据
const dailyData = await getStockDataForTimeframe(symbol, startDate, today, 'daily'); // 获取日线数据
return dailyData.map(c => c.close);
}
/**
* 计算在特定价格路径下滚仓策略的收益
* @param pricePath 价格路径数组
* @param params 策略参数
* @returns 策略收益结果
*/
function calculateStrategyReturns(pricePath, params) {
const { initialShares, feePerTrade, downPercent, upPercent, tradingRatio, stopLossPercent, } = params;
const initialPrice = pricePath[0];
// 初始化状态
let currentShares = initialShares;
let totalInvestment = initialShares * initialPrice;
let avgCost = initialPrice;
let cashBalance = Math.floor(initialShares * tradingRatio) * initialPrice;
// let cashBalance = 0;
let totalFees = 0;
let tradingPosition = Math.floor(initialShares * tradingRatio);
// 跟踪买入状态
let hasBought = false;
let lastBuyPrice = 0;
let lastTradeDay = 0;
// 跟踪止损状态
let stopLossCount = 0;
let lastStopLossDay = 0;
const trades = [];
let hasStopLoss = false;
// 遍历价格路径
for (let day = 1; day < pricePath.length; day++) {
const currentPrice = pricePath[day];
// 检查是否触发止损
if (currentPrice <= initialPrice * (1 - stopLossPercent) &&
currentShares > 0) {
// 执行清仓
const sellValue = currentShares * currentPrice;
cashBalance += sellValue - feePerTrade;
totalFees += feePerTrade;
// 记录交易
const stopLossTrade = {
day,
type: 'stopLoss',
price: currentPrice,
shares: currentShares,
value: sellValue,
fee: feePerTrade,
newShares: 0,
newAvgCost: 0,
cycleProfitLoss: sellValue - currentShares * avgCost - feePerTrade * 2,
};
trades.push(stopLossTrade);
// 更新状态
totalInvestment = 0;
currentShares = 0;
avgCost = 0;
hasBought = false;
lastTradeDay = day;
lastStopLossDay = day;
stopLossCount++;
hasStopLoss = true;
continue;
}
// 如果未买入状态,检查是否满足买入条件
if (!hasBought) {
// 止损之后再次买入信号为当前股价为上次股价的110%时
let reBuyAfterStopLoss = false;
if (hasStopLoss) {
hasStopLoss = false;
tradingPosition = initialShares;
const stopLossPrice = pricePath[lastStopLossDay];
reBuyAfterStopLoss = currentPrice >= stopLossPrice * 1.1;
}
// 价格下跌达到触发条件
if (currentPrice <= pricePath[lastTradeDay] * (1 - downPercent) ||
reBuyAfterStopLoss) {
// 执行买入
const buyValue = tradingPosition * currentPrice;
const buyFee = feePerTrade;
cashBalance -= buyValue + buyFee;
totalFees += buyFee;
// 更新持股和成本
currentShares += tradingPosition;
totalInvestment += buyValue + buyFee;
avgCost = totalInvestment / currentShares;
// 记录交易
const buyTrade = {
day,
type: reBuyAfterStopLoss ? 'reBuy' : 'buy',
price: currentPrice,
shares: tradingPosition,
value: buyValue,
fee: buyFee,
newShares: currentShares,
newAvgCost: avgCost,
};
trades.push(buyTrade);
// 更新状态
hasBought = true;
lastBuyPrice = currentPrice;
lastTradeDay = day;
}
}
// 如果已买入状态,检查是否满足卖出条件
else {
// 价格上涨达到触发条件
if (currentPrice >= lastBuyPrice * (1 + upPercent)) {
// 执行卖出
const sellValue = tradingPosition * currentPrice;
cashBalance += sellValue - feePerTrade;
totalFees += feePerTrade;
// 更新持股和成本
totalInvestment =
totalInvestment * ((currentShares - tradingPosition) / currentShares);
currentShares -= tradingPosition;
avgCost = totalInvestment / currentShares;
// 计算单次循环利润
const cycleProfitLoss = sellValue - tradingPosition * lastBuyPrice - feePerTrade * 2;
// 记录交易
const sellTrade = {
day,
type: 'sell',
price: currentPrice,
shares: tradingPosition,
value: sellValue,
fee: feePerTrade,
newShares: currentShares,
newAvgCost: avgCost,
cycleProfitLoss,
};
trades.push(sellTrade);
// 更新状态
hasBought = false;
lastTradeDay = day;
}
}
}
// 计算最终结果
const finalPrice = pricePath[pricePath.length - 1];
const finalMarketValue = currentShares * finalPrice;
const totalReturn = finalMarketValue + cashBalance - initialShares * initialPrice;
const returnRate = (totalReturn / (initialShares * initialPrice)) * 100;
return {
initialInvestment: initialShares * initialPrice,
finalShares: currentShares,
finalAvgCost: avgCost,
finalMarketValue,
cashBalance,
totalFees,
totalTrades: trades.length,
totalReturn,
returnRate,
breakevenGrowthNeeded: avgCost > 0 ? (avgCost / finalPrice - 1) * 100 : 0,
trades,
stopLossCount,
};
}
/**
* 分析滚仓策略在多种市场情景下的预期收益
* @param params 策略和模拟参数
* @returns 综合分析结果
*/
async function analyzeExpectedReturns(params) {
const pricePath = await getPrices(params.symbol);
// 计算策略收益
const result = calculateStrategyReturns(pricePath, params);
return {
simulationParams: {
initialPrice: pricePath[0],
currentPrice: pricePath[pricePath.length - 1],
stopLossPercent: params.stopLossPercent,
},
averageResults: {
averageTotalReturn: result.totalReturn,
averageReturnRate: result.returnRate,
averageTrades: result.trades,
averageFinalCost: result.finalAvgCost,
stopLossCount: result.stopLossCount,
},
allResults: result,
};
}
/**
* 格式化分析结果输出
* @param analysis 分析结果
* @returns 格式化的字符串输出
*/
function formatAnalysisResult(analysis) {
const { simulationParams, averageResults } = analysis;
let output = `# 滚仓策略预期收益分析报告\n\n`;
output += `## 模拟参数\n`;
output += `- 初始价格: ${simulationParams.initialPrice.toFixed(2)}元\n`;
output += `- 当前价格: ${simulationParams.currentPrice.toFixed(2)}元\n`;
output += `- 止损设置: ${(simulationParams.stopLossPercent * 100).toFixed(2)}%\n`;
output += `## 平均预期结果\n`;
output += `- 平均总收益: ${averageResults.averageTotalReturn.toFixed(2)}元\n`;
output += `- 平均收益率: ${averageResults.averageReturnRate.toFixed(2)}%\n`;
output += `- 止损触发次数: ${averageResults.stopLossCount}\n`;
if (averageResults.averageFinalCost) {
output += `- 平均最终成本: ${averageResults.averageFinalCost.toFixed(2)}元\n`;
if (averageResults.averageFinalCost < simulationParams.initialPrice) {
const costReduction = (1 - averageResults.averageFinalCost / simulationParams.initialPrice) *
100;
output += `- 策略平均可降低成本${costReduction.toFixed(2)}%,有效减轻了套牢风险。\n`;
}
}
else {
output += `- 最终状态: 已全部清仓\n`;
}
output += `- 交易: ${JSON.stringify(averageResults.averageTrades, null, 2)}\n`;
return output;
}
/**
* 运行滚仓策略的期待收益分析
* @param params 分析参数
* @returns 格式化的分析结果
*/
async function runExpectedReturnsAnalysis(params) {
const analysis = await analyzeExpectedReturns(params);
return formatAnalysisResult(analysis);
}
// 使用示例
const sampleParams = {
symbol: 'TSLA',
initialShares: 10,
feePerTrade: 5,
downPercent: 0.03,
upPercent: 0.05,
tradingRatio: 0.3,
stopLossPercent: 0.1, // 10%止损线
};
// 运行分析示例
const analysisReport = await runExpectedReturnsAnalysis(sampleParams);
console.log(analysisReport);
// const result = compareVolatilityScenarios(sampleParams);
// console.log(result);
// 导出函数
export { getPrices, calculateStrategyReturns, analyzeExpectedReturns, runExpectedReturnsAnalysis, };