bool isDefined = false;
object axis = null;
try
{
    axis = this.ChartDetails.Chart.LeftYAxis;
    isDefined = true;
}
catch(RuntimeBinderException)
{ }
This is what happens at runtime in the first place. (When you access a property the 'dynamic' piece of things only happens when a first-chance exception gets handled by the object's override of DynamicObject's TryGetMember and TrySetMember
Some objects (like ExpandoObject) are actually dictionaries under the hood and you can check them directly as follows:
bool isDefined = ((IDictionary<string, object>)this.ChartDetails.Chart)
    .ContainsKey("LeftYAxis");
Basically: without knowing what actual type ChartDetails.Chart is (if it's an ExpandoObject a plain ol' subclass of object or a subclass of DynamicObject) there's no way besides the try/catch above.  If you wrote the code for ChartDetails and Chart or have access to the source code you can determine what methods exist for the object and use those to check.