Selected Answer
Greedy
Don't overwrite Target- it is set by the Worksheet_Change event (as with other events).
This code should do what you want:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge <> 1 Or Intersect(Target, Range("C1:D20")) Is Nothing Then Exit Sub
If Cells(Target.Row, 5) = "Buy" Then Call Speak
End Sub
This first line checks that only a single cell has been changed in range C1:D20 since these would lead to changes in E1:E20 (if not, it exits the sub).
Then second line checks if that value of the cell in column E is now "Buy" and if so calls your sub. The code in bold above means "the cell in the same row as the changed cell (in C or D) but column 5 (= column E)"
Note that you don't need to have a block If (If <<test>> then...(Else)... End If) in the case that a simple action is needed if the test is met (=True) and you don't need an actrion if it isn't.
Hope this fixes your problem.