ThinkScript ---> Excel Question

tommytx

Member
Is there any way under the sun to connect TOS thinkscript to the outside world..

I have a need to get tos think script to talk to the outside world.. Nothing complex.. very simple.. I have thought of the following ideas but they all seem overdone and too complex for such a simple task.. or should be simple. .but its not.. as TS does not talk to text files and or anything else that is connected to the outside world..
1. I know it can be done via Microsoft Excel stuff but that is a long learning curve and seems so over done for such a simple project.

2. All i really need is for TS (think script) to enter a single digit or single character into a text file or into anything that can be read by the outside world like a php program
actually a single character would be best as with a single digit the outside commands would be limited to 10 commands.. However with a single character the commands could be expanded to 52, as both lower case and upper case commands could be sent..

3. i had thought about having TS print a digit to the top left hand side of the screen and then have external program like php or any other external source parse the top left for one character or digit and use ocr to convert it to text.. and it could check for new commands each second.. But my lord that is way to complex for such a simple project.

4. Next i thought about the new addition to TS that uses a log file and simply place the command there, but i doubt the log file is text and i am not sure where its locate so that i can attempt to parse it.. TS could write the command for the outside world into its log file and possibly be parsed by an outside source.. Just searching for ideas.

So before I run off like a mad man and spend a ton of time with this i am hoping one of you experts has solved this problem many eons ago and can give me some ideas. And possibly some one may be familiar enough with how TS talks to excel and they may know a quicky short method to do a one character deal without all the shenagin's that would be required to talk to TS on a long term basis such as storing data (of which i have no knowlege of how that works... I may just have to bite the bullet and study the connection between Microsoft Excel and make that work but, I definitely do not look forward to that learning curve for something so simple..

I would really appreciate some guidance here... as it must have been done before.. as i hate re-inventing the wheel..

Thanks in advance.
 
Last edited by a moderator:
Solution
Thanks I was hoping for something simple.. but i guess carrying on a conversation with think script is not a simple task.. So thanks very much i can make this work.. but i may still give think script a shot at talking to excel as i doubt that it would be much more complex than your script... Thanks
again..

What did you mean by "It will run a week before i restart it?

Also looking at your example which is very helpful i can just skip all the excel stuff since ahk knows what a text file is and can simply write something into text that will work... So you gave me some great ideas to work with...but not being familiar that much with AHK i am sure it knows how to handle a simple thing like a text file and can be done in two lines of...
Is there any way under the sun to connect TOS thinkscript to the outside world..

I have a need to get tos think script to talk to the outside world.. Nothing complex.. very simple.. I have thought of the following ideas but they all seem overdone and too complex for such a simple task.. or should be simple. .but its not.. as TS does not talk to text files and or anything else that is connected to the outside world..
1. I know it can be done via Microsoft Excel stuff but that is a long learning curve and seems so over done for such a simple project.

2. All i really need is for TS (think script) to enter a single digit or single character into a text file or into anything that can be read by the outside world like a php program
actually a single character would be best as with a single digit the outside commands would be limited to 10 commands.. However with a single character the commands could be expanded to 52, as both lower case and upper case commands could be sent..

3. i had thought about having TS print a digit to the top left hand side of the screen and then have external program like php or any other external source parse the top left for one character or digit and use ocr to convert it to text.. and it could check for new commands each second.. But my lord that is way to complex for such a simple project.

4. Next i thought about the new addition to TS that uses a log file and simply place the command there, but i doubt the log file is text and i am not sure where its locate so that i can attempt to parse it.. TS could write the command for the outside world into its log file and possibly be parsed by an outside source.. Just searching for ideas.

So before I run off like a mad man and spend a ton of time with this i am hoping one of you experts has solved this problem many eons ago and can give me some ideas. And possibly some one may be familiar enough with how TS talks to excel and they may know a quicky short method to do a one character deal without all the shenagin's that would be required to talk to TS on a long term basis such as storing data (of which i have no knowlege of how that works... I may just have to bite the bullet and study the connection between Microsoft Excel and make that work but, I definitely do not look forward to that learning curve for something so simple..

I would really appreciate some guidance here... as it must have been done before.. as i hate re-inventing the wheel..

Thanks in advance.
I use AutoHotKey 2.0 to communicate from TOS to Excel. The AHK script proves to be reliable, It will run a week before I restart it.

If you're looking for just a digit or character to update a status, I would recommend that you have TOS drive the logic to a label as a color. Looking for a color is much more reliable than OCR. For instance, I look for a "Buy" status when my indicator is 8+ indicated by the COLOR.LIGHT_GREEN. The spaces at the start of the label provide an area will be the color I'm looking for.

The TOS Study drives the action like the below:

##### Snip from TOS #####
AddLabel(if Total_UP >= 8 then 1 else 0, " Total_UP: " + Total_UP, Color.LIGHT_GREEN);

The AHK script opens an Excel spreadsheet using native commands like the below.

; ##### Snip from AHK #####
try {
xl := ComObjActive("Excel.Application")
} catch {
xl := ComObject("Excel.Application")
}

; Open the workbook and make the Excel application visible.
wb := xl.Workbooks.Open(xl_filePath)
ws := wb.Worksheets("Sheet1")

The AHK looks for the signal color and appends to the Excel file.

;##### Snip from AHK #####

; Color to look for
green_signal := 0x90EE90

; And we have a loop that looks for color change
sub_WatchForColor(*)
{
loop
{
WinActivate("Main@thinkorswim")
Sleep(2000)

; Watch for indicator color
signal_color := PixelGetColor(signal_xpos, signal_ypos)
Sleep(2000)

if (signal_color = green_signal) ; the LONG signal is detected
{
ExcelAppend(ws, "Long Signal", "Detected")
}
}

}

; Subroutine for appending the Excel File
ExcelAppend(excelWorksheet, dataType, dataText)
{
now_date := FormatTime(A_Now, "yyyy-MM-dd")
now_time := FormatTime(A_Now, "HH:mm:ss")

lastRow := excelWorksheet.Cells(excelWorksheet.Rows.Count, 1).End(-4162).Row
newRow := lastRow + 1
excelWorksheet.Cells(newRow, 1).Value := now_date
excelWorksheet.Cells(newRow, 2).Value := now_time
excelWorksheet.Cells(newRow, 3).Value := dataType
excelWorksheet.Cells(newRow, 4).Value := dataText
wb.Save()
}
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Thanks I was hoping for something simple.. but i guess carrying on a conversation with think script is not a simple task.. So thanks very much i can make this work.. but i may still give think script a shot at talking to excel as i doubt that it would be much more complex than your script... Thanks
again..

What did you mean by "It will run a week before i restart it?

Also looking at your example which is very helpful i can just skip all the excel stuff since ahk knows what a text file is and can simply write something into text that will work... So you gave me some great ideas to work with...but not being familiar that much with AHK i am sure it knows how to handle a simple thing like a text file and can be done in two lines of code.. so that php can pick it up and run with it... I don't really need excel but just mentioned it since I knew think script was a tine bit friendly with excel.. not very friendly but a little. I just needed a temp location in the outside world..from think script.



Thanks again..
 
Last edited:
Thanks I was hoping for something simple.. but i guess carrying on a conversation with think script is not a simple task.. So thanks very much i can make this work.. but i may still give think script a shot at talking to excel as i doubt that it would be much more complex than your script... Thanks
again..

What did you mean by "It will run a week before i restart it?

Also looking at your example which is very helpful i can just skip all the excel stuff since ahk knows what a text file is and can simply write something into text that will work... So you gave me some great ideas to work with...but not being familiar that much with AHK i am sure it knows how to handle a simple thing like a text file and can be done in two lines of code.. so that php can pick it up and run with it... I don't really need excel but just mentioned it since I knew think script was a tine bit friendly with excel.. not very friendly but a little. I just needed a temp location in the outside world..from think script.



Thanks again..
The AHK script will run for over a week without crashing. I manually shut the AHK down over the weekend and restart it on Sunday afternoon for another week of data gathering.
 
Thanks I was hoping for something simple.. but i guess carrying on a conversation with think script is not a simple task.. So thanks very much i can make this work.. but i may still give think script a shot at talking to excel as i doubt that it would be much more complex than your script... Thanks
again..

What did you mean by "It will run a week before i restart it?

Also looking at your example which is very helpful i can just skip all the excel stuff since ahk knows what a text file is and can simply write something into text that will work... So you gave me some great ideas to work with...but not being familiar that much with AHK i am sure it knows how to handle a simple thing like a text file and can be done in two lines of code.. so that php can pick it up and run with it... I don't really need excel but just mentioned it since I knew think script was a tine bit friendly with excel.. not very friendly but a little. I just needed a temp location in the outside world..from think script.



Thanks again..
I'll add that TOS has a built in Real Time Data (RTD) service that can directly feed data to Excel. Its easy to push Marketwatch / Quotes data to Excel. The real time data is easily added to Excel as described in the following video:
 
Solution
there is a post on here about using a 2nd party program to look for color changes on the tos screen and act on them...

macro recorder

Playground
Macro Recorder Questions For ThinkOrSwim
https://usethinkscript.com/threads/macro-recorder-questions-for-thinkorswim.14339/#post-117687

a video explaing a setup
https://drive.google.com/file/d/1uq1IMBaUw96mFSAgL02d1LQcJT_3V8W_/view

---------------------------


maybe using the api might be an option
https://usethinkscript.com/threads/api-question.21343/
 
Last edited:
I use AutoHotKey 2.0 to communicate from TOS to Excel. The AHK script proves to be reliable, It will run a week before I restart it.

If you're looking for just a digit or character to update a status, I would recommend that you have TOS drive the logic to a label as a color. Looking for a color is much more reliable than OCR. For instance, I look for a "Buy" status when my indicator is 8+ indicated by the COLOR.LIGHT_GREEN. The spaces at the start of the label provide an area will be the color I'm looking for.

The TOS Study drives the action like the below:

##### Snip from TOS #####
AddLabel(if Total_UP >= 8 then 1 else 0, " Total_UP: " + Total_UP, Color.LIGHT_GREEN);

The AHK script opens an Excel spreadsheet using native commands like the below.

; ##### Snip from AHK #####
try {
xl := ComObjActive("Excel.Application")
} catch {
xl := ComObject("Excel.Application")
}

; Open the workbook and make the Excel application visible.
wb := xl.Workbooks.Open(xl_filePath)
ws := wb.Worksheets("Sheet1")

The AHK looks for the signal color and appends to the Excel file.

;##### Snip from AHK #####

; Color to look for
green_signal := 0x90EE90

; And we have a loop that looks for color change
sub_WatchForColor(*)
{
loop
{
WinActivate("Main@thinkorswim")
Sleep(2000)

; Watch for indicator color
signal_color := PixelGetColor(signal_xpos, signal_ypos)
Sleep(2000)

if (signal_color = green_signal) ; the LONG signal is detected
{
ExcelAppend(ws, "Long Signal", "Detected")
}
}

}

; Subroutine for appending the Excel File
ExcelAppend(excelWorksheet, dataType, dataText)
{
now_date := FormatTime(A_Now, "yyyy-MM-dd")
now_time := FormatTime(A_Now, "HH:mm:ss")

lastRow := excelWorksheet.Cells(excelWorksheet.Rows.Count, 1).End(-4162).Row
newRow := lastRow + 1
excelWorksheet.Cells(newRow, 1).Value := now_date
excelWorksheet.Cells(newRow, 2).Value := now_time
excelWorksheet.Cells(newRow, 3).Value := dataType
excelWorksheet.Cells(newRow, 4).Value := dataText
wb.Save()
}

@whoDAT
from reading the very detailed data that you have written on using color to allow you to control TOS to far greater lengths than any of the simple ThinkScripts that do not allow full round trips.

I have been studying your notes and have a strong understanding of the principle that you are using and would greatly appreciate any additional information that you would be willing to share. Such as the AhK code used to run the loop waiting for colors to accomplish specific tasks.
A video would be great, but just some of the coding used with the AHK loop would be super beneficial.

I fully understand how the colors are generated by ThinkScript on the top left corner of the TOS chart, but I'm not totally clear about developing all the AHK software to run the look checking and waiting for certain specific events...

Thank you so much in advance, as your comments and videos have made my life so much easier. Any little tidbit would help. Thanks.
 
Last edited by a moderator:
@whoDAT
from reading the very detailed data that you have written on using color to allow you to control TOS to far greater lengths than any of the simple ThinkScripts that do not allow full round trips.

I have been studying your notes and have a strong understanding of the principle that you are using and would greatly appreciate any additional information that you would be willing to share. Such as the AhK code used to run the loop waiting for colors to accomplish specific tasks.
A video would be great, but just some of the coding used with the AHK loop would be super beneficial.

I fully understand how the colors are generated by ThinkScript on the top left corner of the TOS chart, but I'm not totally clear about developing all the AHK software to run the look checking and waiting for certain specific events...

Thank you so much in advance, as your comments and videos have made my life so much easier. Any little tidbit would help. Thanks.
 
Use this only for for testing. As in a production environment it will do real trades. And that is risky beyond all getup.

First the TOS environment must be set up. You'll need to make sure the auto-send trade is enabled. As the autotrading program will hit a button, and doesn't confirm - it just executes. You also need to ensure the trading size and TIF are accurate to what you want to do. Use limits and stops if you want to do that also. The position panel must be open to show "Working Only" trades.

There are lots and lots of locations to get correct. Use AHK's "Window Spy". You'll be looking for the Buy, Sell and Flatten buttons and locations of the indicators for limits, stops, orders, working orders.

- Limit Banner - Limits and Stops - these are down the center of the trading screen. We're looking for the red and green panels that show if you added limits and stops. You're to enter the left, right, top and bottom of the area where these occur.

- Position Banner - the left of the chart shows a green or red banner where you entered a trade. We're bounding the left, right, top and bottom of where we'd find that banner.

- Action Buttons - Buy Market, Sell Market, Flatten - We need the upper left (ul) and bottom right (br) of each of these buttons.

- Position Panel - This is the little up arrow button on the bottom left corner that opens the position panel. We need to view if the position panel is showing stop and limit trades.

- Order Short and Long - This is a general area of where we can find red or green to indicate our stop and limit orders in the position panel. We need to find the color of these to determine the order status.

Alright so what does this do.

1) We look for a cyan and yellow color change in the top left of the trade. That indicates that a new candle printed.

2) We then look for a change of the signal, go long or short.

3) Then process the trade.

The below study will will create a block that changes between cyan and yellow each candle.

Code:
declare upper;
def cbn = HighestAll(BarNumber());

AddLabel(cbn % 2 == 1, "      .      .", Color.YELLOW, location = Location.TOP_LEFT);
AddLabel(cbn % 2 != 1, "      .      .", Color.CYAN, location = Location.TOP_LEFT);

Then you need a signal that corresponds to when you want to enter a trade long or short. Add code like the below to you favorite study.

Code:
AddLabel(pos == 1, ".      .    UP: ", Color.LIGHT_GREEN);
AddLabel(pos == -1, ".      .    DOWN: ", Color.LIGHT_RED);

And the - DO NOT USE THIS UNDER ANY CIRCUMSTANCE - Autohotkey code:


Code:
#Requires AutoHotkey v2.0

; v 3.3 - Added third signal (long, short and now flatten).
; v 3.2 - Fixed keeping track of the current order and what to do when the signal changes.
; v 3.1 - Added global error messages
; v 3.0 - Updated GUI - rid of start/stop TOS. Use labels to display statuses.
; v 2.9 - Added move limit to defined $profit. Code to progress towards increased profit with limit moves. Moved events file to screenshot folder. Get price from position panel.
; v 2.8 - Added don't reenter trade if limited out. Wait for next signal. Find P/L.
; v 2.7 - Added flattenout subroutine to get out of trade instead of limitmove
; v 2.6 - Added screenshot to each cycle.
; v 2.5 - Moved buy sell to subroutines. changed limit move to % move towards price. changed trigger to be change of color right corner.
; v 2.4 - Handle orange color = flatten without buying, close excel and remove lock from editing
; v 2.3 - Open workbooks line 120
; v 2.2 - Added 15 min pause after buy or sell. This will stop double purchasing if stopped out.
; v 2.1 - Stable release

; FORCE Run as Administrator
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run '*RunAs "' A_ScriptFullPath '" /restart'
        else
            Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
    }
    ExitApp
}

xl_filePath := A_Desktop . "\SCREENSHOTS\Autotrade_Events.xlsx"

try {
    xl := ComObjActive("Excel.Application")
} catch {
    xl := ComObject("Excel.Application")
}

; Open the workbook and make the Excel application visible.
wb := xl.Workbooks.Open(xl_filePath)
ws :=  wb.Worksheets("Sheet1")


Capture2TextPath := A_Desktop . "\Capture2Text\Capture2Text_CLI.exe"

Destination := A_Desktop . "\SCREENSHOTS"
IfNotExist(Destination)          ; if not already a folder create one
      {
        DirCreate(Destination)
    }

CoordMode "Pixel", "Screen"
CoordMode "Mouse", "Screen"


; signal between bar changes
cyan_signal := 0X00FFFF        ; CYAN            used for bar changes
yellow_signal := 0xFFFF00    ; YELLOW        used for bar chagens
magenta_signal := 0xFF00FF    ; MAGENTA

; where to look for bar change (each bar change in upper right) this is for timing.
bar_xpos := 36
bar_ypos := 204

; signal colors to trigger events
green_signal := 0x90EE90    ; LIGHT_GREEN    used for long
red_signal := 0xFF3F00        ; LIGHT_RED        used for short
orange_signal := 0xFFA500    ; LIGHT_ORANGE    used for flatten

; where to look for main buy/sell signal
signal_xpos := 95
signal_ypos := 204


; colors of many buttons used
buymkt_inactive_color := 0x08663A
buymkt_active_color := 0x0A7F48
sellmkt_inactive_color := 0x973030
sellmkt_active_color := 0xAE3D3D
flatten_inactive_color := 0x4A4A4A
flatten_active_color := 0x595959
sell_order_color := 0x922E2E
buy_order_color := 0X075832

; where are limit and stops relative to position
limit_banner_color_green := 0x075832
limit_banner_color_red := 0X96110E
limit_banner_height := 20
limit_banner_width := 120
limit_banner_top_x := 820
limit_banner_top_y := 184
limit_banner_bot_x := 940
limit_banner_bot_y := 715

; shows when in a trade this is the red or green bubble with a line - find the bubble
position_banner_color_red := 0X96110E
position_banner_color_green := 0x075832
position_banner_height := 20
position_banner_width := 120
position_banner_top_x := 25
position_banner_top_y := 215
position_banner_bot_x := 145
position_banner_bot_y := 733


; used for test and click function. test to see if button is there before pressing it
buymkt_ul_xpos := 1520
buymkt_ul_ypos := 143
buymkt_dr_xpos := 1597
buymkt_dr_ypos := 171
sellmkt_ul_xpos := 1620
sellmkt_ul_ypos := 143
sellmkt_dr_xpos := 1697
sellmkt_dr_ypos := 171
flatten_ul_xpos := 1719
flatten_ul_ypos := 143
flatten_dr_xpos := 1790
flatten_dr_ypos := 171

; to open the position panel
pos_button_x := 125
pos_button_y := 1012

; to find the order short or long in the position panel
order_topx := 1334
order_topy := 948
order_botx := 1344
order_boty := 1020


; was supposed to hide the teamviewer panel
teamviewer_xpos := 1590
teamviewer_ypos := 921
teamviewer_color_xpos := 1780
teamviewer_color_ypos := 840
teamviewer_panel_xpos := 1592
teamviewer_panel_ypos := 891
teamviewer_color := 0x2747D0

; to keep the window refreshed
return_x := 1167
return_y := 586



;#####################
global debug_mode := 0                ; Set debug_mode to 1 (one) to have messageboxes show up which subroutine is being called
;#####################

ExcelAppend(ws, "Program Start", "Autotrade")

TimeString := "Time: " . FormatTime(, "HH:mm.ss")
BarChangeString := "Bar Change: " . FormatTime(, "HH:mm.ss")
SignalString := "No Signal Change"
ErrorString := "No Errors Seen"

MyGui := Gui()
MyGui.SetFont("s14 w700", "Segoe UI")
MyGui.Add("Text", "Center w230", "Autotrade for the win!")
TimeDisplay := MyGui.Add("Text", "Center w230", TimeString)
BarChangeDisplay := MyGui.Add("Text", "Center w230", BarChangeString)
SignalChangeDisplay := MyGui.Add("Text", "Center w230", SignalString)
MyGui.SetFont("s10 w700", "Segoe UI")
ErrorDisplay := MyGui.Add("Edit", "r10 w230 ReadOnly +Wrap +Vertical", ErrorString)
Spacer := MyGui.Add("Text", "Center w230", " ")
Radio1 := MyGui.AddRadio("w230",    "Press to Run Watch/Trade")
Radio1.OnEvent("Click", sub_WatchTrade)
Radio2 := MyGui.AddRadio("w230",    "Press to Pause Watch/Trade")
Radio2.OnEvent("Click", sub_PauseTrade)
Radio8 := MyGui.AddRadio("w230",    "Press to Close Watch/Trade")
Radio8.OnEvent("Click", sub_CloseAT)
MyGui.Show("w250")


OnError(MyErrorHandler)

MyErrorHandler(err, mode) {
    ErrorDisplay.Value := err.Message . " at: " . FormatTime(, "HH:mm.ss")
    return 1
}


sub_WatchTrade(*)
 {

initial_restart := 1        ; On initial restart, disregard the first signal or we'll process a LONG, SHORT or FLATTEN
last_limit_move := -1        ; Keep track of the last limit dollar move. Force this only to increase.

Try
    {
    prev_bar_color := 0x123456        ; a dummy value
    prev_signal_color :=0x123456    ; a dummy value
    
    order_stat := GetOrderStatus()
    current_state := "OUT"                ; "LONG", "SHORT", or "OUT"
    if (order_stat = 2 || order_stat = 4)   ; If SHORT order with limits is detected
        {
        current_state := "SHORT"
        }
    if (order_stat = 1 || order_stat = 3)   ; If LONG order with limits is detected
        {
        current_state := "LONG"
        }
    
    
    loop
        {
        TimeDisplay.Value := current_state . ": " . FormatTime(, "HH:mm.ss")
        if (debug_mode = 1)
            {
            msgbox "Watch/Trade loop"
            }
        
        if (debug_mode = 1)
            {
            msgbox current_state
            }

        if WinExist("Sponsored session")    ; kill TeamViewer
            {
            WinClose("Sponsored session")
            }
            
;        sub_CloseTVSidePanel()      ; close that pesky TeamViewer Bottom Side Panel
        
        WinActivate("Main@thinkorswim")
        Sleep(500)
        MouseClick "left", return_x, return_y       
    
        ; Watch for change of color in upper left box - yellow or cyan changes with each bar.
        bar_color := PixelGetColor(bar_xpos, bar_ypos)
        
        if (debug_mode = 1)
            {
            msgbox "bar_color: " bar_color " - prev_bar_color: " prev_bar_color
            }
        
        if (bar_color != prev_bar_color)            ; change from bar to bar
            {
            BarChangeDisplay.Value := "BarChange: " . FormatTime(, "HH:mm.ss")
    
            ; Find signal indicator color

            signal_color := PixelGetColor(signal_xpos, signal_ypos)
            Sleep(500)
            
            prev_bar_color := bar_color
            
            if (debug_mode = 1)
                {
                msgbox "signal_color: " signal_color
                msgbox "checking for green signal"
                }
            
            if (signal_color != prev_signal_color)
                {
                order_stat := GetOrderStatus()
                current_state := "OUT"                ; "LONG", "SHORT", or "OUT"
                if (order_stat = 2 || order_stat = 4)   ; If SHORT order with limits is detected
                    {
                        current_state := "SHORT"
                    }
                if (order_stat = 1 || order_stat = 3)   ; If LONG order with limits is detected
                    {
                        current_state := "LONG"
                    }                   
                
                }


            if (signal_color = green_signal && current_state != "LONG" && initial_restart != 1)        ; the LONG signal is detected and wasn't recently limited out
                {
                SignalChangeDisplay.Value := "BUY LONG: " . FormatTime(, "HH:mm.ss")
                sub_ProcessLong()
                prev_signal_color := signal_color
                current_state := "LONG"
;                sub_Screenshot()
                }
                    
            if (debug_mode = 1)
                {
                msgbox "not green signal / checking for red"
                }
    
            if (signal_color = red_signal && current_state != "SHORT" && initial_restart != 1)           ; the SHORT signal is detected and wasn't recently limited out
                {
                SignalChangeDisplay.Value := "SELL SHORT: " . FormatTime(, "HH:mm.ss")
                sub_ProcessShort()
                prev_signal_color := signal_color
                current_state := "SHORT"
;                sub_Screenshot()
                }

            if (debug_mode = 1)
                {
                msgbox "not red signal"
                }

            if (signal_color = orange_signal && initial_restart != 1)        ; the FLATTEN signal is detected
                {
                SignalChangeDisplay.Value := "FLATTEN: " . FormatTime(, "HH:mm.ss")
                sub_FlattenOut()
                prev_signal_color := signal_color
                current_state := "OUT"
;                sub_Screenshot()
                }
    
            
            if (initial_restart = 1)
                {
                initial_restart := 0
                sleep(50)
                }           

            }
            
        Sleep(12000)        ; wait 12 seconds til we do it all again

                
        MouseClick "left", return_x + 8, return_y + 8
        
        }
    }   
    
Catch
    {
    ErrorDisplay.Value := A_LastError . " at: " . FormatTime(, "HH:mm.ss")
    }
}


sub_PauseTrade(*)
    {
    loop
        {
        Sleep(60000)
        }
    }

sub_CloseAT(*)
    {
    Excel := ComObjActive("Excel.Application")
    loop Excel.workbooks.count
        {
            if fileexist(Excel.workbooks(a_index).fullname)
            Excel.Workbooks(a_index).save
        }
    Excel.quit()

    ExitApp
    }


sub_ProcessLong(*)
    {

    if (debug_mode = 1)
        {
        msgbox "sub_ProcessLong"
        }

    ord_stat := GetOrderStatus()
    if (ord_stat = 2 || ord_stat = 4)   ; If short order with or without limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)

        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
        
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)

    if (ord_stat = 0)   ; If flatten button is inactive we should place LONG order
        {
        ; Buy
        TestAndClick(buymkt_ul_xpos, buymkt_ul_ypos, buymkt_dr_xpos, buymkt_dr_ypos, buymkt_inactive_color, buymkt_active_color)
        Sleep(15000)
        
        ; Update status of GUI
        ExcelAppend(ws, "Long", "Complete")
        }
    }


sub_ProcessShort(*)
    {
    
    if (debug_mode = 1)
        {
        msgbox "sub_ProcessShort"
        }
    
    ord_stat := GetOrderStatus()
    if (ord_stat = 1 || ord_stat = 3)   ; If long order with limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)
            
;        msgbox "Flattened"
        
        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
        
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)

    if (ord_stat = 0)   ; If flatten button is inactive we should place SHORT order
        {
        ; Sell
        TestAndClick(sellmkt_ul_xpos, sellmkt_ul_ypos, sellmkt_dr_xpos, sellmkt_dr_ypos, sellmkt_inactive_color, sellmkt_active_color)
        Sleep(15000)

        ; Update status of GUI
        ExcelAppend(ws, "Short", "Complete")
        }
    }


sub_FlattenOut(*)
    {
    
    if (debug_mode = 1)
        {
        msgbox "sub_FlattenOut"
        }
    
    ord_stat := GetOrderStatus()
    if (ord_stat = 1 || ord_stat = 2 || ord_stat = 3 || ord_stat = 4)   ; If order with or without limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)
            
;        msgbox "Flattened"
        
        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
        
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)
    }



sub_Status(*)
{
    ord_stat := GetOrderStatus()
    
    ExcelAppend(ws, "Order Status", ord_stat)

    if (ord_stat = 0)
        {
        msgbox "No orders"
        }
    else if (ord_stat = 1)
        {
        msgbox "Buy (unfilled) with sell limits"
        }
    else if (ord_stat = 2)
        {
        msgbox "Sell (unfilled) with buy limits"
        }
    else if (ord_stat = 3)
        {
        msgbox "Bought with sell limits"
        }   
    else if (ord_stat = 4)
        {
        msgbox "Sold with buy limits"
        }
}


; GetOrderStatus will open the order book and return one of 5 values
; 0 - is for no orders
; 1 - Orders detected - Buy (unfilled) with sell limits
; 2 - Orders detected - Sell (unfilled) with buylimits
; 3 - Orders detected - Bought with sell limits
; 4 - Orders detected - Sold with buy limits

GetOrderStatus(*)
{
    WinActivate("Main@thinkorswim")
    Sleep(500)
    
    MouseClick "left", pos_button_x, pos_button_y   ; open the position tab
    Sleep(4000)
    MouseMove return_x, return_y

    top_order_sell := PixelSearch(&top_sell_x, &top_sell_y, order_topx, order_topy, order_botx, order_boty, sell_order_color)
    top_order_buy := PixelSearch(&top_buy_x, &top_buy_y, order_topx, order_topy, order_botx, order_boty, buy_order_color)
    bot_order_sell := PixelSearch(&bot_sell_x, &bot_sell_y, order_botx, order_boty, order_topx, order_topy, sell_order_color)
    bot_order_buy := PixelSearch(&bot_buy_x, &bot_buy_y, order_botx, order_boty, order_topx, order_topy, buy_order_color)

;    msgbox PixelGetColor(order_topx, 932) ", Top"
;    msgbox PixelGetColor(order_topx, 960) ",  Bottom"
;    msgbox top_sell_y " -sell- " bot_sell_y
;    msgbox top_buy_y  " -buy- "  bot_buy_y

    if (top_order_sell AND top_order_buy)
        {
        if (top_sell_y > top_buy_y)
            {
            order_status := 1
            }
        else if (top_sell_y < top_buy_y)
            {
            order_status := 2
            }
        }
    else if (top_order_sell = 0 AND top_order_buy = 0)
        {   
            order_status := 0
            short_bubble := PixelSearch(&Pos_LimitX, &Pos_LimitY, position_banner_top_x, position_banner_top_y, position_banner_bot_x, position_banner_bot_y, position_banner_color_red)
            long_bubble := PixelSearch(&Pos_LimitX, &Pos_LimitY, position_banner_top_x, position_banner_top_y, position_banner_bot_x, position_banner_bot_y, position_banner_color_green)
            
            if (short_bubble)
                {
                order_status := 4
                }
            
            if (long_bubble)
                {
                order_status := 3
                }
        }
    else
        {
        if (top_order_sell) ;
            {
            order_status := 3
            }
        else if (top_order_buy) ;
            {
            order_status := 4
            }
        }
    return order_status
}




TestAndClick(upper_left_x, upper_left_y, lower_right_x, lower_right_y, inactive_color, active_color)
{
;    msgbox PixelGetColor(upper_left_x, upper_left_y) ", " upper_left_x ", " upper_left_y
    inactive_res := PixelSearch(&inactive_x, &inactive_y, upper_left_x, upper_left_y, lower_right_x, lower_right_y, inactive_color)
    Sleep(500)
;    msgbox inactive_res
    if (inactive_res = 1)
        {
        MouseMove inactive_x, inactive_y
        Sleep(500)
        highlight_color := PixelGetColor(inactive_x, inactive_y)
;        msgbox highlight_color
        if (active_color = highlight_color)
            {
            MouseClick "left", inactive_x, inactive_y
;            msgbox "clicked"
            }
        }
    else
        {
        MouseMove return_x, return_y
        Sleep(500)
        fnd_color := PixelGetColor(upper_left_x, upper_left_y)
;        msgbox fnd_color
        }
    MouseMove return_x, return_y
}



; This function checks if a specific Excel file is open.
; It returns the Workbook object if found, otherwise returns false.
IsExcelFileOpen(filePath)
{
    try {
        ; Attempt to connect to a running instance of Excel
        excelApp := ComObjActive("Excel.Application")
        
        ; Extract the file name from the full path
        fileName := SubStr(filePath, InStr(filePath, "\", , -1) + 1)
        
        ; Loop through all open workbooks
        for workbook in excelApp.Workbooks {
            if (workbook.Name == fileName) {
                return workbook ; Return the Workbook object
            }
        }
    } catch {
        ; Excel is not running, so the file cannot be open
        return false
    }
    return false
}


ExcelAppend(excelWorksheet, dataType, dataText)
{
    now_date := FormatTime(A_Now, "yyyy-MM-dd")
    now_time := FormatTime(A_Now, "HH:mm:ss")

    lastRow := excelWorksheet.Cells(excelWorksheet.Rows.Count, 1).End(-4162).Row
        newRow := lastRow + 1
    excelWorksheet.Cells(newRow, 1).Value := now_date
    excelWorksheet.Cells(newRow, 2).Value := now_time
    excelWorksheet.Cells(newRow, 3).Value := dataType
    excelWorksheet.Cells(newRow, 4).Value := dataText
    wb.Save()
}


sub_Screenshot(*)
{
    WinActivate("Main@thinkorswim")
    currentDateTime := FormatTime(A_Now, "yyyy-MM-dd_HHmmss")
    
    exePath := '"' . A_ProgramFiles . '\IrfanView\i_view64.exe"'
    destPath := '"' . Destination . '\capture_$U(' . currentDateTime . ').jpg"'
    cmd := exePath . ' /capture=3 /crop=(0,0,2000,1400) /resize=(200,140) /jpgq=60 /convert=' . destPath
;    msgbox cmd
    RunWait(cmd)
}



; Close Teamviewer side panel
sub_CloseTVSidePanel(*)
{
        tv_color := PixelGetColor(teamviewer_color_xpos, teamviewer_color_ypos)
        if (tv_color = teamviewer_color)
            {
            MouseClick "left", teamviewer_panel_xpos, teamviewer_panel_ypos
            }
}

Your TOS trader workspace should look something like this:

Untitled.png
 
Use this only for for testing. As in a production environment it will do real trades. And that is risky beyond all getup.

First the TOS environment must be set up. You'll need to make sure the auto-send trade is enabled. As the autotrading program will hit a button, and doesn't confirm - it just executes. You also need to ensure the trading size and TIF are accurate to what you want to do. Use limits and stops if you want to do that also. The position panel must be open to show "Working Only" trades.

There are lots and lots of locations to get correct. Use AHK's "Window Spy". You'll be looking for the Buy, Sell and Flatten buttons and locations of the indicators for limits, stops, orders, working orders.

- Limit Banner - Limits and Stops - these are down the center of the trading screen. We're looking for the red and green panels that show if you added limits and stops. You're to enter the left, right, top and bottom of the area where these occur.

- Position Banner - the left of the chart shows a green or red banner where you entered a trade. We're bounding the left, right, top and bottom of where we'd find that banner.

- Action Buttons - Buy Market, Sell Market, Flatten - We need the upper left (ul) and bottom right (br) of each of these buttons.

- Position Panel - This is the little up arrow button on the bottom left corner that opens the position panel. We need to view if the position panel is showing stop and limit trades.

- Order Short and Long - This is a general area of where we can find red or green to indicate our stop and limit orders in the position panel. We need to find the color of these to determine the order status.

Alright so what does this do.

1) We look for a cyan and yellow color change in the top left of the trade. That indicates that a new candle printed.

2) We then look for a change of the signal, go long or short.

3) Then process the trade.

The below study will will create a block that changes between cyan and yellow each candle.

Code:
declare upper;
def cbn = HighestAll(BarNumber());

AddLabel(cbn % 2 == 1, "      .      .", Color.YELLOW, location = Location.TOP_LEFT);
AddLabel(cbn % 2 != 1, "      .      .", Color.CYAN, location = Location.TOP_LEFT);

Then you need a signal that corresponds to when you want to enter a trade long or short. Add code like the below to you favorite study.

Code:
AddLabel(pos == 1, ".      .    UP: ", Color.LIGHT_GREEN);
AddLabel(pos == -1, ".      .    DOWN: ", Color.LIGHT_RED);

And the - DO NOT USE THIS UNDER ANY CIRCUMSTANCE - Autohotkey code:


Code:
#Requires AutoHotkey v2.0

; v 3.3 - Added third signal (long, short and now flatten).
; v 3.2 - Fixed keeping track of the current order and what to do when the signal changes.
; v 3.1 - Added global error messages
; v 3.0 - Updated GUI - rid of start/stop TOS. Use labels to display statuses.
; v 2.9 - Added move limit to defined $profit. Code to progress towards increased profit with limit moves. Moved events file to screenshot folder. Get price from position panel.
; v 2.8 - Added don't reenter trade if limited out. Wait for next signal. Find P/L.
; v 2.7 - Added flattenout subroutine to get out of trade instead of limitmove
; v 2.6 - Added screenshot to each cycle.
; v 2.5 - Moved buy sell to subroutines. changed limit move to % move towards price. changed trigger to be change of color right corner.
; v 2.4 - Handle orange color = flatten without buying, close excel and remove lock from editing
; v 2.3 - Open workbooks line 120
; v 2.2 - Added 15 min pause after buy or sell. This will stop double purchasing if stopped out.
; v 2.1 - Stable release

; FORCE Run as Administrator
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run '*RunAs "' A_ScriptFullPath '" /restart'
        else
            Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
    }
    ExitApp
}

xl_filePath := A_Desktop . "\SCREENSHOTS\Autotrade_Events.xlsx"

try {
    xl := ComObjActive("Excel.Application")
} catch {
    xl := ComObject("Excel.Application")
}

; Open the workbook and make the Excel application visible.
wb := xl.Workbooks.Open(xl_filePath)
ws :=  wb.Worksheets("Sheet1")


Capture2TextPath := A_Desktop . "\Capture2Text\Capture2Text_CLI.exe"

Destination := A_Desktop . "\SCREENSHOTS"
IfNotExist(Destination)          ; if not already a folder create one
      {
        DirCreate(Destination)
    }

CoordMode "Pixel", "Screen"
CoordMode "Mouse", "Screen"


; signal between bar changes
cyan_signal := 0X00FFFF        ; CYAN            used for bar changes
yellow_signal := 0xFFFF00    ; YELLOW        used for bar chagens
magenta_signal := 0xFF00FF    ; MAGENTA

; where to look for bar change (each bar change in upper right) this is for timing.
bar_xpos := 36
bar_ypos := 204

; signal colors to trigger events
green_signal := 0x90EE90    ; LIGHT_GREEN    used for long
red_signal := 0xFF3F00        ; LIGHT_RED        used for short
orange_signal := 0xFFA500    ; LIGHT_ORANGE    used for flatten

; where to look for main buy/sell signal
signal_xpos := 95
signal_ypos := 204


; colors of many buttons used
buymkt_inactive_color := 0x08663A
buymkt_active_color := 0x0A7F48
sellmkt_inactive_color := 0x973030
sellmkt_active_color := 0xAE3D3D
flatten_inactive_color := 0x4A4A4A
flatten_active_color := 0x595959
sell_order_color := 0x922E2E
buy_order_color := 0X075832

; where are limit and stops relative to position
limit_banner_color_green := 0x075832
limit_banner_color_red := 0X96110E
limit_banner_height := 20
limit_banner_width := 120
limit_banner_top_x := 820
limit_banner_top_y := 184
limit_banner_bot_x := 940
limit_banner_bot_y := 715

; shows when in a trade this is the red or green bubble with a line - find the bubble
position_banner_color_red := 0X96110E
position_banner_color_green := 0x075832
position_banner_height := 20
position_banner_width := 120
position_banner_top_x := 25
position_banner_top_y := 215
position_banner_bot_x := 145
position_banner_bot_y := 733


; used for test and click function. test to see if button is there before pressing it
buymkt_ul_xpos := 1520
buymkt_ul_ypos := 143
buymkt_dr_xpos := 1597
buymkt_dr_ypos := 171
sellmkt_ul_xpos := 1620
sellmkt_ul_ypos := 143
sellmkt_dr_xpos := 1697
sellmkt_dr_ypos := 171
flatten_ul_xpos := 1719
flatten_ul_ypos := 143
flatten_dr_xpos := 1790
flatten_dr_ypos := 171

; to open the position panel
pos_button_x := 125
pos_button_y := 1012

; to find the order short or long in the position panel
order_topx := 1334
order_topy := 948
order_botx := 1344
order_boty := 1020


; was supposed to hide the teamviewer panel
teamviewer_xpos := 1590
teamviewer_ypos := 921
teamviewer_color_xpos := 1780
teamviewer_color_ypos := 840
teamviewer_panel_xpos := 1592
teamviewer_panel_ypos := 891
teamviewer_color := 0x2747D0

; to keep the window refreshed
return_x := 1167
return_y := 586



;#####################
global debug_mode := 0                ; Set debug_mode to 1 (one) to have messageboxes show up which subroutine is being called
;#####################

ExcelAppend(ws, "Program Start", "Autotrade")

TimeString := "Time: " . FormatTime(, "HH:mm.ss")
BarChangeString := "Bar Change: " . FormatTime(, "HH:mm.ss")
SignalString := "No Signal Change"
ErrorString := "No Errors Seen"

MyGui := Gui()
MyGui.SetFont("s14 w700", "Segoe UI")
MyGui.Add("Text", "Center w230", "Autotrade for the win!")
TimeDisplay := MyGui.Add("Text", "Center w230", TimeString)
BarChangeDisplay := MyGui.Add("Text", "Center w230", BarChangeString)
SignalChangeDisplay := MyGui.Add("Text", "Center w230", SignalString)
MyGui.SetFont("s10 w700", "Segoe UI")
ErrorDisplay := MyGui.Add("Edit", "r10 w230 ReadOnly +Wrap +Vertical", ErrorString)
Spacer := MyGui.Add("Text", "Center w230", " ")
Radio1 := MyGui.AddRadio("w230",    "Press to Run Watch/Trade")
Radio1.OnEvent("Click", sub_WatchTrade)
Radio2 := MyGui.AddRadio("w230",    "Press to Pause Watch/Trade")
Radio2.OnEvent("Click", sub_PauseTrade)
Radio8 := MyGui.AddRadio("w230",    "Press to Close Watch/Trade")
Radio8.OnEvent("Click", sub_CloseAT)
MyGui.Show("w250")


OnError(MyErrorHandler)

MyErrorHandler(err, mode) {
    ErrorDisplay.Value := err.Message . " at: " . FormatTime(, "HH:mm.ss")
    return 1
}


sub_WatchTrade(*)
 {

initial_restart := 1        ; On initial restart, disregard the first signal or we'll process a LONG, SHORT or FLATTEN
last_limit_move := -1        ; Keep track of the last limit dollar move. Force this only to increase.

Try
    {
    prev_bar_color := 0x123456        ; a dummy value
    prev_signal_color :=0x123456    ; a dummy value
   
    order_stat := GetOrderStatus()
    current_state := "OUT"                ; "LONG", "SHORT", or "OUT"
    if (order_stat = 2 || order_stat = 4)   ; If SHORT order with limits is detected
        {
        current_state := "SHORT"
        }
    if (order_stat = 1 || order_stat = 3)   ; If LONG order with limits is detected
        {
        current_state := "LONG"
        }
   
   
    loop
        {
        TimeDisplay.Value := current_state . ": " . FormatTime(, "HH:mm.ss")
        if (debug_mode = 1)
            {
            msgbox "Watch/Trade loop"
            }
       
        if (debug_mode = 1)
            {
            msgbox current_state
            }

        if WinExist("Sponsored session")    ; kill TeamViewer
            {
            WinClose("Sponsored session")
            }
           
;        sub_CloseTVSidePanel()      ; close that pesky TeamViewer Bottom Side Panel
       
        WinActivate("Main@thinkorswim")
        Sleep(500)
        MouseClick "left", return_x, return_y      
   
        ; Watch for change of color in upper left box - yellow or cyan changes with each bar.
        bar_color := PixelGetColor(bar_xpos, bar_ypos)
       
        if (debug_mode = 1)
            {
            msgbox "bar_color: " bar_color " - prev_bar_color: " prev_bar_color
            }
       
        if (bar_color != prev_bar_color)            ; change from bar to bar
            {
            BarChangeDisplay.Value := "BarChange: " . FormatTime(, "HH:mm.ss")
   
            ; Find signal indicator color

            signal_color := PixelGetColor(signal_xpos, signal_ypos)
            Sleep(500)
           
            prev_bar_color := bar_color
           
            if (debug_mode = 1)
                {
                msgbox "signal_color: " signal_color
                msgbox "checking for green signal"
                }
           
            if (signal_color != prev_signal_color)
                {
                order_stat := GetOrderStatus()
                current_state := "OUT"                ; "LONG", "SHORT", or "OUT"
                if (order_stat = 2 || order_stat = 4)   ; If SHORT order with limits is detected
                    {
                        current_state := "SHORT"
                    }
                if (order_stat = 1 || order_stat = 3)   ; If LONG order with limits is detected
                    {
                        current_state := "LONG"
                    }                  
               
                }


            if (signal_color = green_signal && current_state != "LONG" && initial_restart != 1)        ; the LONG signal is detected and wasn't recently limited out
                {
                SignalChangeDisplay.Value := "BUY LONG: " . FormatTime(, "HH:mm.ss")
                sub_ProcessLong()
                prev_signal_color := signal_color
                current_state := "LONG"
;                sub_Screenshot()
                }
                   
            if (debug_mode = 1)
                {
                msgbox "not green signal / checking for red"
                }
   
            if (signal_color = red_signal && current_state != "SHORT" && initial_restart != 1)           ; the SHORT signal is detected and wasn't recently limited out
                {
                SignalChangeDisplay.Value := "SELL SHORT: " . FormatTime(, "HH:mm.ss")
                sub_ProcessShort()
                prev_signal_color := signal_color
                current_state := "SHORT"
;                sub_Screenshot()
                }

            if (debug_mode = 1)
                {
                msgbox "not red signal"
                }

            if (signal_color = orange_signal && initial_restart != 1)        ; the FLATTEN signal is detected
                {
                SignalChangeDisplay.Value := "FLATTEN: " . FormatTime(, "HH:mm.ss")
                sub_FlattenOut()
                prev_signal_color := signal_color
                current_state := "OUT"
;                sub_Screenshot()
                }
   
           
            if (initial_restart = 1)
                {
                initial_restart := 0
                sleep(50)
                }          

            }
           
        Sleep(12000)        ; wait 12 seconds til we do it all again

               
        MouseClick "left", return_x + 8, return_y + 8
       
        }
    }  
   
Catch
    {
    ErrorDisplay.Value := A_LastError . " at: " . FormatTime(, "HH:mm.ss")
    }
}


sub_PauseTrade(*)
    {
    loop
        {
        Sleep(60000)
        }
    }

sub_CloseAT(*)
    {
    Excel := ComObjActive("Excel.Application")
    loop Excel.workbooks.count
        {
            if fileexist(Excel.workbooks(a_index).fullname)
            Excel.Workbooks(a_index).save
        }
    Excel.quit()

    ExitApp
    }


sub_ProcessLong(*)
    {

    if (debug_mode = 1)
        {
        msgbox "sub_ProcessLong"
        }

    ord_stat := GetOrderStatus()
    if (ord_stat = 2 || ord_stat = 4)   ; If short order with or without limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)

        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
       
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)

    if (ord_stat = 0)   ; If flatten button is inactive we should place LONG order
        {
        ; Buy
        TestAndClick(buymkt_ul_xpos, buymkt_ul_ypos, buymkt_dr_xpos, buymkt_dr_ypos, buymkt_inactive_color, buymkt_active_color)
        Sleep(15000)
       
        ; Update status of GUI
        ExcelAppend(ws, "Long", "Complete")
        }
    }


sub_ProcessShort(*)
    {
   
    if (debug_mode = 1)
        {
        msgbox "sub_ProcessShort"
        }
   
    ord_stat := GetOrderStatus()
    if (ord_stat = 1 || ord_stat = 3)   ; If long order with limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)
           
;        msgbox "Flattened"
       
        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
       
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)

    if (ord_stat = 0)   ; If flatten button is inactive we should place SHORT order
        {
        ; Sell
        TestAndClick(sellmkt_ul_xpos, sellmkt_ul_ypos, sellmkt_dr_xpos, sellmkt_dr_ypos, sellmkt_inactive_color, sellmkt_active_color)
        Sleep(15000)

        ; Update status of GUI
        ExcelAppend(ws, "Short", "Complete")
        }
    }


sub_FlattenOut(*)
    {
   
    if (debug_mode = 1)
        {
        msgbox "sub_FlattenOut"
        }
   
    ord_stat := GetOrderStatus()
    if (ord_stat = 1 || ord_stat = 2 || ord_stat = 3 || ord_stat = 4)   ; If order with or without limits is detected
        {
        ; Flatten
        TestAndClick(flatten_ul_xpos, flatten_ul_ypos, flatten_dr_xpos, flatten_dr_ypos, flatten_inactive_color, flatten_active_color)
        ; Wait for the trade to go through
        Sleep(15000)
           
;        msgbox "Flattened"
       
        ; Update status of GUI
        ExcelAppend(ws, "Flatten", "Complete")
        }
       
    WinActivate("Main@thinkorswim")
    Sleep(2500)
    ord_stat := GetOrderStatus()
    Sleep(5000)
    }



sub_Status(*)
{
    ord_stat := GetOrderStatus()
   
    ExcelAppend(ws, "Order Status", ord_stat)

    if (ord_stat = 0)
        {
        msgbox "No orders"
        }
    else if (ord_stat = 1)
        {
        msgbox "Buy (unfilled) with sell limits"
        }
    else if (ord_stat = 2)
        {
        msgbox "Sell (unfilled) with buy limits"
        }
    else if (ord_stat = 3)
        {
        msgbox "Bought with sell limits"
        }  
    else if (ord_stat = 4)
        {
        msgbox "Sold with buy limits"
        }
}


; GetOrderStatus will open the order book and return one of 5 values
; 0 - is for no orders
; 1 - Orders detected - Buy (unfilled) with sell limits
; 2 - Orders detected - Sell (unfilled) with buylimits
; 3 - Orders detected - Bought with sell limits
; 4 - Orders detected - Sold with buy limits

GetOrderStatus(*)
{
    WinActivate("Main@thinkorswim")
    Sleep(500)
   
    MouseClick "left", pos_button_x, pos_button_y   ; open the position tab
    Sleep(4000)
    MouseMove return_x, return_y

    top_order_sell := PixelSearch(&top_sell_x, &top_sell_y, order_topx, order_topy, order_botx, order_boty, sell_order_color)
    top_order_buy := PixelSearch(&top_buy_x, &top_buy_y, order_topx, order_topy, order_botx, order_boty, buy_order_color)
    bot_order_sell := PixelSearch(&bot_sell_x, &bot_sell_y, order_botx, order_boty, order_topx, order_topy, sell_order_color)
    bot_order_buy := PixelSearch(&bot_buy_x, &bot_buy_y, order_botx, order_boty, order_topx, order_topy, buy_order_color)

;    msgbox PixelGetColor(order_topx, 932) ", Top"
;    msgbox PixelGetColor(order_topx, 960) ",  Bottom"
;    msgbox top_sell_y " -sell- " bot_sell_y
;    msgbox top_buy_y  " -buy- "  bot_buy_y

    if (top_order_sell AND top_order_buy)
        {
        if (top_sell_y > top_buy_y)
            {
            order_status := 1
            }
        else if (top_sell_y < top_buy_y)
            {
            order_status := 2
            }
        }
    else if (top_order_sell = 0 AND top_order_buy = 0)
        {  
            order_status := 0
            short_bubble := PixelSearch(&Pos_LimitX, &Pos_LimitY, position_banner_top_x, position_banner_top_y, position_banner_bot_x, position_banner_bot_y, position_banner_color_red)
            long_bubble := PixelSearch(&Pos_LimitX, &Pos_LimitY, position_banner_top_x, position_banner_top_y, position_banner_bot_x, position_banner_bot_y, position_banner_color_green)
           
            if (short_bubble)
                {
                order_status := 4
                }
           
            if (long_bubble)
                {
                order_status := 3
                }
        }
    else
        {
        if (top_order_sell) ;
            {
            order_status := 3
            }
        else if (top_order_buy) ;
            {
            order_status := 4
            }
        }
    return order_status
}




TestAndClick(upper_left_x, upper_left_y, lower_right_x, lower_right_y, inactive_color, active_color)
{
;    msgbox PixelGetColor(upper_left_x, upper_left_y) ", " upper_left_x ", " upper_left_y
    inactive_res := PixelSearch(&inactive_x, &inactive_y, upper_left_x, upper_left_y, lower_right_x, lower_right_y, inactive_color)
    Sleep(500)
;    msgbox inactive_res
    if (inactive_res = 1)
        {
        MouseMove inactive_x, inactive_y
        Sleep(500)
        highlight_color := PixelGetColor(inactive_x, inactive_y)
;        msgbox highlight_color
        if (active_color = highlight_color)
            {
            MouseClick "left", inactive_x, inactive_y
;            msgbox "clicked"
            }
        }
    else
        {
        MouseMove return_x, return_y
        Sleep(500)
        fnd_color := PixelGetColor(upper_left_x, upper_left_y)
;        msgbox fnd_color
        }
    MouseMove return_x, return_y
}



; This function checks if a specific Excel file is open.
; It returns the Workbook object if found, otherwise returns false.
IsExcelFileOpen(filePath)
{
    try {
        ; Attempt to connect to a running instance of Excel
        excelApp := ComObjActive("Excel.Application")
       
        ; Extract the file name from the full path
        fileName := SubStr(filePath, InStr(filePath, "\", , -1) + 1)
       
        ; Loop through all open workbooks
        for workbook in excelApp.Workbooks {
            if (workbook.Name == fileName) {
                return workbook ; Return the Workbook object
            }
        }
    } catch {
        ; Excel is not running, so the file cannot be open
        return false
    }
    return false
}


ExcelAppend(excelWorksheet, dataType, dataText)
{
    now_date := FormatTime(A_Now, "yyyy-MM-dd")
    now_time := FormatTime(A_Now, "HH:mm:ss")

    lastRow := excelWorksheet.Cells(excelWorksheet.Rows.Count, 1).End(-4162).Row
        newRow := lastRow + 1
    excelWorksheet.Cells(newRow, 1).Value := now_date
    excelWorksheet.Cells(newRow, 2).Value := now_time
    excelWorksheet.Cells(newRow, 3).Value := dataType
    excelWorksheet.Cells(newRow, 4).Value := dataText
    wb.Save()
}


sub_Screenshot(*)
{
    WinActivate("Main@thinkorswim")
    currentDateTime := FormatTime(A_Now, "yyyy-MM-dd_HHmmss")
   
    exePath := '"' . A_ProgramFiles . '\IrfanView\i_view64.exe"'
    destPath := '"' . Destination . '\capture_$U(' . currentDateTime . ').jpg"'
    cmd := exePath . ' /capture=3 /crop=(0,0,2000,1400) /resize=(200,140) /jpgq=60 /convert=' . destPath
;    msgbox cmd
    RunWait(cmd)
}



; Close Teamviewer side panel
sub_CloseTVSidePanel(*)
{
        tv_color := PixelGetColor(teamviewer_color_xpos, teamviewer_color_ypos)
        if (tv_color = teamviewer_color)
            {
            MouseClick "left", teamviewer_panel_xpos, teamviewer_panel_ypos
            }
}

Your TOS trader workspace should look something like this:

View attachment 27156
Thank you whodat that is so very generous of you.. I will forever be in your debt...Thank you! Thank YOu!
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
1117 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top