reply to #223
here is something to experiment with,
uses the crossing of 2 averages to create buy and sell signals.
default is HULL , 22 and 66 lengths
when a buy happens , a horizontal line starts drawing at the buy price.
can pick 2 dates and choose to enable the range. if dates are on a weekend, it will find the next trading date.
can pick a starting balance.
on a buy signal, the maximum quantity of shares are calculated.
labels,
trading date range , if date range is enabled.
current account value
gain amount. (green or red)
if date range is enabled, then the average lines and signals and bubbles are restricted to within the date range.
can turn on test bubbles and lines. bubbles show shares , buy amount, balance,
Code:
# chat223_profit_loss1
#https://usethinkscript.com/threads/chatgpt-bard-other-ai-scripts-which-cant-be-used-in-thinkorswim.13822/page-12#post-139305
# post223
# profit and loss report, between 2 dates
def na = Double.NaN;
def bn = BarNumber();
def price = round(close, 2);
input starting_capital = 10000;
# date yyyymmdd
input start_date = 20240303;
#input start_date = 20240304;
input finish_date = 20240316;
#input finish_date = 20240317;
#input finish_date = 20240318;
input enable_trade_range = yes;
addlabel(enable_trade_range, asprice(start_date) + " to " + asprice(finish_date), color.yellow);
def date_en = if !enable_trade_range then 1
else (DaysFromDate(start_date) >= 0 and DaysTillDate(finish_date) >= 0);
def date_start = enable_trade_range and DaysFromDate(start_date)[1] < 0 and DaysFromDate(start_date) >= 0;
def date_end = enable_trade_range and DaysfromDate(finish_date)[1] <0 and DaysfromDate(finish_date) >= 0;
addverticalline(date_start, "START " + asprice(start_date), color.cyan);
addverticalline(date_end, "END " + asprice(finish_date), color.cyan);
addchartbubble(0, low,
DaysFromDate(start_date) + " F\n" +
DaysTillDate(finish_date) + " T"
, color.yellow, no);
#input avg1_type = AverageType.exponential;
#input avg1_type = AverageType.Simple;
input avg1_type = AverageType.HULL;
input avg1_length = 22;
def avg1 = MovingAverage(avg1_type, price, avg1_length );
#input avg2_type = AverageType.Simple;
input avg2_type = AverageType.HULL;
input avg2_length = 66;
def avg2 = MovingAverage(avg2_type, price, avg2_length );
input show_average_lines = yes;
plot zavg1 = if show_average_lines and date_en then avg1 else na;
plot zavg2 = if show_average_lines and date_en then avg2 else na;
zavg1.SetDefaultColor(Color.CYAN);
zavg1.SetLineWeight(1);
zavg1.HideBubble();
zavg2.SetDefaultColor(Color.YELLOW);
zavg2.SetLineWeight(1);
zavg2.HideBubble();
def xup = avg1 crosses above avg2;
def xdwn = avg1 crosses below avg2;
# Check the crossings and perform buys/sells
# use all money on each trade
def shares;
def shares_value;
def current_capital;
def buy_price;
if bn == 1 then {
buy_price = 0;
shares = 0;
shares_value = 0;
current_capital = starting_capital;
} else if date_en and xup then {
# buy
buy_price = price;
shares = floor(current_capital[1] / buy_price);
shares_value = round(shares * price, 2);
current_capital = current_capital[1] - shares_value;
} else if date_en and xdwn then {
# sell
buy_price = 0;
shares = 0;
shares_value = 0;
current_capital = current_capital[1] + (shares[1] * price);
} else {
buy_price = buy_price[1];
shares = shares[1];
shares_value = shares * price;
current_capital = current_capital[1];
}
def current_value = Current_Capital + (shares[0] * price);
def gain_per = round(100 * (current_value-starting_capital)/starting_capital,2);
AddLabel(yes, "Initial Capital: $" + starting_capital, color.yellow);
AddLabel(yes, "Current Capital: $" + current_value , color.yellow);
AddLabel(yes, "Gain " + gain_per + " %" , (if gain_per > 0 then color.green else color.red));
# buy price line
plot zb = if buy_price == 0 then na
else if isnan(close[1]) then na
else buy_price;
input test_bubbles = no;
addchartbubble(test_bubbles and date_en and (xup or xdwn), low,
price + "\n" +
shares + " shares\n" +
shares_value + " $\n" +
current_capital + " $\n"
, color.yellow, no);
addverticalline(test_bubbles and date_en and xup, "buy", color.green);
addverticalline(test_bubbles and date_en and xdwn, "sell", color.red);
#
Thank you very much halcyonguy, thank you very much for the excellent script, it is very useful for backtesting! I am asking you and whoever may be interested, if there is a possibility of taking it to the next level, improving this script in two steps: 1) that it also considers short operations for the calculation of profits, and 2) if there is a possibility of making it The code compares all combinations, at their different lengths, of the two moving averages (and better yet, if possible, of all types of moving averages with each other), and then indicates which of them obtained the best profit. If possible, it would be a great and very useful tool for all users. -
I added a basic example of this, but I need someone experienced to incorporate it so that it works properly. -Thank you in advance.-
# Define the minimum and maximum lengths for the moving averages
input minLength = 5;
input maxLength = 50;
# List of moving average types to test
def maTypes = {SMA, WMA, HullMA, EMA}; # You can add other types of moving averages as needed
# Variables to store the best combination found
def bestProfit = Double.NEGATIVE_INFINITY;
def bestParams = "";
# Loop to test all combinations
foreach length in minLength..maxLength {
foreach maType in maTypes {
# Calculate profits for the current combination
def currentProfit = CalculateProfits(maType, length);
# Update the best combination if one with greater profits is found
if (currentProfit > bestProfit) {
bestProfit = currentProfit;
bestParams = maType + " Length: " + length;
}
}
}
# Print the best combination found
AddLabel(yes, "Best combination: " + bestParams + ", Profit: " + bestProfit);