Skip to content

Commit

Permalink
added function "getFormattedGainsLosses" and deleted unused function
Browse files Browse the repository at this point in the history
  • Loading branch information
EtoileScintillante committed Aug 7, 2024
1 parent f96576d commit 310a203
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 73 deletions.
165 changes: 100 additions & 65 deletions src/data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,71 +187,6 @@ std::string getFormattedPrice(const std::string &symbol, bool markdown, bool clo
return resultStream.str();
}

void fetchAndWriteEquityData(const std::string &symbol, const std::string &duration)
{
// Define the current timestamp as the end time
std::time_t endTime = std::time(nullptr);

// Calculate the start time based on the duration
std::time_t startTime = endTime;
startTime -= getDurationInSeconds(duration);
if (startTime == endTime)
{
std::cerr << "Invalid duration format. Examples of supported formats: 7m, 1w, 3y, 6d, where m = month, w = week, y = year, and d = day." << std::endl;
return;
}

// Convert timestamps to strings
std::ostringstream startTimestamp, endTimestamp;
startTimestamp << startTime;
endTimestamp << endTime;

// Build the URL for historical data
std::string url = "https://query1.finance.yahoo.com/v7/finance/download/" + symbol +
"?period1=" + startTimestamp.str() + "&period2=" + endTimestamp.str() +
"&interval=1d&events=history";

// Fetch historical data using the URL
std::string response = httpGet(url);

// Check if response contains an error or is empty
if (response.find("404 Not Found: No data found, symbol may be delisted") != std::string::npos)
{
std::cerr << "Symbol not found or delisted: " << symbol << std::endl;
return;
}
if (response.empty())
{
std::cerr << "Failed to fetch data from the server." << std::endl;
return;
}

// Get the current directory where the executable is located
std::string exePath = std::filesystem::current_path().string(); // Use std::experimental::filesystem in C++14

// Construct the file path to the "data" folder
std::string chartPath = exePath + "/../data/"; // Assuming the "data" folder is one level up from the executable

// Create the "data" folder if it doesn't exist
std::filesystem::create_directory(chartPath); // Use std::experimental::filesystem in C++14

// Construct the file path for the output file inside the "data" folder
std::string filename = chartPath + symbol + "_" + duration + ".txt";
std::ofstream outFile(filename);

if (outFile)
{
outFile << response;
std::cout << "Data for " << symbol << " in the last " << duration << " has been written to " << filename << std::endl;
}
else
{
std::cerr << "Failed to open file: " << filename << std::endl;
}

outFile.close();
}

Metrics fetchMetrics(const std::string &symbol)
{
Metrics equityMetrics;
Expand Down Expand Up @@ -566,4 +501,104 @@ std::string getFormattedJSON(const std::string &pathToJson, const std::string &k
}

return getFormattedPrices(symbols, names, descriptions, markdown, closedWarning);
}

std::string getFormattedGainsLosses(const std::string &symbol, const std::string &duration, bool markdown)
{
// Fetch data
Metrics data = fetchMetrics(symbol);
std::vector<std::vector<std::string>> ohlcData = fetchOHLCData(symbol, duration);
if (ohlcData.empty())
{
std::cout << "No OHLC data available." << std::endl;
return "";
}

// Vector to store percentage changes with corresponding dates
std::vector<GainLoss> changes;

// Iterate over data and calculate the percentage change for each day
for (const auto &day : ohlcData)
{
if (day.size() < 5) continue; // Ensure there's enough data
const std::string &date = day[0];
double open = std::stod(day[1]);
double close = std::stod(day[4]);

// Calculate percentage change
double percentageChange = ((close - open) / open) * 100.0;
changes.emplace_back(date, percentageChange, open, close);
}

// Sort changes to find top 5 gains and losses
std::sort(changes.begin(), changes.end(), [](const GainLoss &a, const GainLoss &b) {
return a.percentageChange > b.percentageChange;
});

// Extract top 5 gains
std::vector<GainLoss> topGains(changes.begin(), changes.begin() + std::min<size_t>(5, changes.size()));
// Extract top 5 losses
std::vector<GainLoss> topLosses(changes.end() - std::min<size_t>(5, changes.size()), changes.end());

// Sort losses from most negative to least negative
std::sort(topLosses.begin(), topLosses.end(), [](const GainLoss &a, const GainLoss &b) {
return a.percentageChange < b.percentageChange;
});

// Format the results
std::ostringstream result;

if (markdown)
{
result << "### Top 5 Gains :chart_with_upwards_trend:\n";
}
else
{
result << "Top 5 Gains:\n";
}
for (size_t i = 0; i < topGains.size(); ++i)
{
if (markdown)
{
result << i + 1 << ". " << topGains[i].date << ": `"
<< std::fixed << std::setprecision(2) << topGains[i].percentageChange
<< "% (open: " << topGains[i].openPrice << " " << data.currency
<< ", close: " << topGains[i].closePrice << " " << data.currency << ")`\n";
}
else
{
result << i + 1 << ". " << topGains[i].date << ": "
<< std::fixed << std::setprecision(2) << topGains[i].percentageChange
<< "% (open: " << topGains[i].openPrice << " " << data.currency
<< ", close: " << topGains[i].closePrice << " " << data.currency << ")\n";
}
}

if (markdown)
{
result << "\n### Top 5 Losses :chart_with_downwards_trend:\n";
}
else
{
result << "\nTop 5 Losses:\n";
}
for (size_t i = 0; i < topLosses.size(); ++i)
{
if (markdown)
{
result << i + 1 << ". " << topLosses[i].date << ": `"
<< std::fixed << std::setprecision(2) << topLosses[i].percentageChange
<< "% (open: " << topLosses[i].openPrice << " " << data.currency
<< ", close: " << topLosses[i].closePrice << " " << data.currency << ")`\n";
}
else
{
result << i + 1 << ". " << topLosses[i].date << ": "
<< std::fixed << std::setprecision(2) << topLosses[i].percentageChange
<< "% (open: " << topLosses[i].openPrice << " " << data.currency
<< ", close: " << topLosses[i].closePrice << " " << data.currency << ")\n";
}
}

return result.str();
}
27 changes: 20 additions & 7 deletions src/include/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ struct Metrics
double avgVol_3mo = 0; // Average daily trading volumes over a 3-month period
};

// Struct used in the getFormattedGainsLosses function
// This way it is easy to save the dates of the biggest gains/losses
struct GainLoss {
std::string date = "-";
double percentageChange = 0;
double openPrice = 0;
double closePrice = 0;

GainLoss(const std::string &d, double p, double o, double c)
: date(d), percentageChange(p), openPrice(o), closePrice(c) {}
};

/// Callback function to write received data to a string.
/// @param ptr Pointer to the received data buffer.
/// @param size Represents the size of each data element in the buffer (typically the size of a single character, byte).
Expand Down Expand Up @@ -85,13 +97,6 @@ std::vector<std::vector<std::string>> fetchOHLCData(const std::string &symbol, c
/// @return A string containing the latest price and % change information.
std::string getFormattedPrice(const std::string &symbol, bool markdown = false, bool closedWarning = false);

/// Function to fetch historical stock/future/index/crypto data from Yahoo Finance and write to a txt file.
/// The txt file will be named {symbol}_{duration}.txt and will be saved in the "data" folder.
/// The interval of the data is one day.
/// @param symbol The symbol of the stock/future/index/crypto.
/// @param duration The duration string in the format: 1y, 6mo, 2w, 12d, etc.
void fetchAndWriteEquityData(const std::string &symbol, const std::string &duration);

/// Function to fetch stock/future/index/crypto metrics from Yahoo Finance API for a single symbol.
/// @param symbol The symbol of the stock/future/index/crypto.
/// @return Metrics struct containing price info, market capitalization and more.
Expand Down Expand Up @@ -130,4 +135,12 @@ std::string getFormattedPrices(std::vector<std::string> symbols, std::vector<std
/// @return A string with the formatted price data (and optionally descriptions).
std::string getFormattedJSON(const std::string &pathToJson, const std::string &key, bool markdown = false, bool description = false, bool closedWarning = false);

/// Function to get the top 5 biggest gains and losses (in percentage change) of a stock/future/index/crypto
/// during a given period. The daily opening and closing prices are used to calculate this.
/// @param symbol The symbol of the stock/future/index/crypto.
/// @param duration The duration/period in the format: 1y, 6mo, 2w, 12d, etc.
/// @param markdown When set to true, the formatted string contains Markdown syntax to make it more visually appealing.
/// @return A formatted string with the biggest gains and losses.
std::string getFormattedGainsLosses(const std::string &symbol, const std::string &duration, bool markdown = false);

#endif // DATA_H
2 changes: 1 addition & 1 deletion src/include/visualize.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void priceGraph(std::string symbol, std::string duration, int mode);
/// @param symbol The symbol of the stock/future/index/crypto.
/// @param duration The duration/period in the format: 1y, 6mo, 2w, 12d, etc.
/// @param withVolume Set to true if you want to plot volumes as well.
/// @note Please note that using OHLCV data of a period >6 months may lead
/// @note Please note that using OHLCV data of a period >12 months may lead
/// to a candlestick chart and volume graph that are not clearly readable. In such cases, the candlesticks
/// and volume bars may appear very thin or small, making it hard to discern the details.
void createCandleChart(std::string symbol, std::string duration, bool withVolume = false);
Expand Down

0 comments on commit 310a203

Please sign in to comment.